contains 方法
不管在c#中还是java中,很多类型都有contains方法。它的原理是什么?
看一个java的例子
http://blog.csdn.net/fwwdn/article/details/6746849
c#中的contains有:
| String.Contains |
| List(T).Contains |
| Enumerable.Contains(TSource) |
| Vector.contains |
| Queue(T).Contains |
| Enumerable.Contains |
| Collection.contains |
| HashSet(T).Contains |
| ICollection(T).Contains |
| Array.contains |
| IQueryable(T).Contains |
| Hashtable.Contains |
| ArrayList.contains |
| Collection(T).Contains |
| Enumerable.Contains(TSource) |
| EntityCollection(TEntity).Contains |
| Stack(T).Contains |
| SortedList.Contains |
| PropertyBag.Contains |
等等。。。。。。。。。
看了下msdn,这些contains的原理,大致分三种
1,默认相等比较器
2,equals
3,hashcode
以List<T> 为例,其contains方法的定义为
// System.Collections.Generic.List<T>
/// <summary>Determines whether an element is in the <see cref="T:System.Collections.Generic.List`1" />.</summary>
/// <returns>true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.List`1" />; otherwise, false.</returns>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.List`1" />. The value can be null for reference types.</param>
[__DynamicallyInvokable]
public bool Contains(T item)
{
if (item == null)
{
for (int i = ; i < this._size; i++)
{
if (this._items[i] == null)
{
return true;
}
}
return false;
}
EqualityComparer<T> @default = EqualityComparer<T>.Default;
for (int j = ; j < this._size; j++)
{
if (@default.Equals(this._items[j], item))
{
return true;
}
}
return false;
}
可以看到,使用了默认相等比较器的方法Equals:EqualityComparer,看一下其定义
http://msdn.microsoft.com/zh-cn/library/ms224763(v=vs.110).aspx
public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
这两个接口只有两个方法,Equals和GetHashCode,但是EqualityComparer是一个抽象类,它实现了IEqualityComparer接口的两个方法且定义为私有方法,却把IEqualityComparer<T>接口的两个方法实现为了抽象方法。
那么因为@default.Equals调用的是IEqualityComparer<T>接口的方法,所以我们要知道Equals的实现方式,关键是在Default的获取上,通过它才可以看到Equals的定义,看一下Default的定义
public static EqualityComparer<T> Default
{
get
{
EqualityComparer<T> equalityComparer = EqualityComparer<T>.defaultComparer;
if (equalityComparer == null)
{
equalityComparer = EqualityComparer<T>.CreateComparer();
EqualityComparer<T>.defaultComparer = equalityComparer;
}
return equalityComparer;
}
}
这里边defaultComparer的定义:(todo volatile 修饰符的定义)
private static volatile EqualityComparer<T> defaultComparer;
我们暂时当它是null的,那么就会调用私有方法CreateComparer了。
private static EqualityComparer<T> CreateComparer()
{
RuntimeType runtimeType = (RuntimeType)typeof(T);
if (runtimeType == typeof(byte))
{
return (EqualityComparer<T>)new ByteEqualityComparer();
}
if (typeof(IEquatable<T>).IsAssignableFrom(runtimeType))
{
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), runtimeType);
}
if (runtimeType.IsGenericType && runtimeType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
RuntimeType runtimeType2 = (RuntimeType)runtimeType.GetGenericArguments()[];
if (typeof(IEquatable<>).MakeGenericType(new Type[]
{
runtimeType2
}).IsAssignableFrom(runtimeType2))
{
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), runtimeType2);
}
}
if (runtimeType.IsEnum && Enum.GetUnderlyingType(runtimeType) == typeof(int))
{
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), runtimeType);
}
return new ObjectEqualityComparer<T>();
}
在这里,根据不同的运行时类型,实例化不同的EqualityComparer子类。在此只看最后一个return(todo 其他子类),ObjectEqualityComparer:这是一个internal的类,我们是用不了的
internal class ObjectEqualityComparer<T> : EqualityComparer<T>
然后我们可以找到Equals,这里会有两个
public override bool Equals(T x, T y)
{
if (x != null)
{
return y != null && x.Equals(y);
}
return y == null;
}
public override bool Equals(object obj)
{
ObjectEqualityComparer<T> objectEqualityComparer = obj as ObjectEqualityComparer<T>;
return objectEqualityComparer != null;
}
我们用到的是第一个(todo,第二个)。我们看到,这里又一次调用了Equals,但是这个Equals很好定位,它就是Object.Equals
如果当前实例是引用类型,Equals(Object) 方法测试引用相等性,并且,对于 Equals(Object) 方法的调用等效于 ReferenceEquals 方法的调用。 引用相等性意味着进行比较的对象变量引用同一个对象。如果当前实例是值类型,Equals(Object) 方法测试值相等性。
派生类通常重写 Object.Equals(Object) 方法实现值相等性。 此外,类型通常还提供其他的重载到 Equals 方法的强类型,通常通过实现 IEquatable<T> 接口。 当您调用 Equals 方法测试是否相等时,应知道是否当前实例重写 Object.Equals 并了解如何解决对 Equals 方法的特定调用。 否则,您可以执行与您预期不同的相等测试,因此,方法可能会返回意外的值。
http://msdn.microsoft.com/zh-cn/library/bsc2ak47.aspx
追下去后:
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
public new static extern bool Equals(object o1, object o2);
我觉得系统内置的类的Equals方法,都会重写的。我们关心的是我们自定义的类是怎么使用Equals的。但是这里开始导入外部的方法了,再进一步不知道该怎么办了(todo 继续追查,extern修饰符的定义)。
http://blog.csdn.net/llddyy123wq/article/details/5620466
--======================================================================================
这条路走不通,换一个类型,试试HashSet<T>,首先找到它的contains方法
public bool Contains(T item)
{
if (this.m_buckets != null)
{
int num = this.InternalGetHashCode(item);
for (int i = this.m_buckets[num % this.m_buckets.Length] - ; i >= ; i = this.m_slots[i].next)
{
if (this.m_slots[i].hashCode == num && this.m_comparer.Equals(this.m_slots[i].value, item))
{
return true;
}
}
}
return false;
}
看了下,m_comparer是IEqualityComparer<T>类型的,所以这里的Equals和上边是一样的。除了Equals,hashset还要比较hashcode,这是比较特别的地方。
contains 方法的更多相关文章
- javaSE27天复习总结
JAVA学习总结 2 第一天 2 1:计算机概述(了解) 2 (1)计算机 2 (2)计算机硬件 2 (3)计算机软件 2 (4)软件开发(理解) 2 (5) ...
- mapreduce多文件输出的两方法
mapreduce多文件输出的两方法 package duogemap; import java.io.IOException; import org.apache.hadoop.conf ...
- 【.net 深呼吸】细说CodeDom(6):方法参数
本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...
- IE6、7下html标签间存在空白符,导致渲染后占用多余空白位置的原因及解决方法
直接上图:原因:该div包含的内容是靠后台进行print操作,输出的.如果没有输出任何内容,浏览器会默认给该空白区域添加空白符.在IE6.7下,浏览器解析渲染时,会认为空白符也是占位置的,默认其具有字 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- [C#] C# 基础回顾 - 匿名方法
C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...
- ArcGIS 10.0紧凑型切片读写方法
首先介绍一下ArcGIS10.0的缓存机制: 切片方案 切片方案包括缓存的比例级别.切片尺寸和切片原点.这些属性定义缓存边界的存在位置,在某些客户端中叠加缓存时匹配这些属性十分重要.图像格式和抗锯齿等 ...
- [BOT] 一种android中实现“圆角矩形”的方法
内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...
- JS 判断数据类型的三种方法
说到数据类型,我们先理一下JavaScript中常见的几种数据类型: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Functi ...
- .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法
.NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...
随机推荐
- 作业八:团队项目——Alpha阶段项目总结
1.项目的预期目标 最初的项目计划实现一款类似微信飞机大战这样的一款模拟飞行游戏,中途也没有变动. 2.目前项目实现的功能. 击落飞机并计分. 3.下阶段我们可以增加游戏更多的功能,以及增加网络在线对 ...
- 黑苹果-IOS学习的开始
深知安装黑苹果的不易,在这里写一下关于我的Thinkpad E430c安装黑苹果教程(Mac版本:Yosemite 10.10.4),希望能够帮助有需要的朋友. 首先贴上我的电脑配置报表: ----- ...
- 学习笔记-- android动画简述
android支持三种类型的动画: ·属性动画 一种补间动画,通过在目标对象的任何属性的两个值之间应用赠了变化,可以生成一种动画效果.这种动画可以用来生成各种效果,例如:改变视图的颜色.透明条.淡入 ...
- 如何通过 js 修改微信浏览器的title?
document.setTitle = function(t) { document.title = t; var i = document.createElement('iframe'); i.sr ...
- C#学习手册
考研学子为何放弃考研?C++开发ArcGis为何无疾而终?C#为何又成为新宠?这一切得一切是人性的扭曲还是道德的败坏,敬请收看接下来的C#学习手册.ps:一天一更.拖更打死.
- Date Range Picker时间插件非常不错,主要体现在选择一个时间区间
地址:http://www.daterangepicker.com/ demo地址:http://tamble.github.io/jquery-ui-daterangepicker/#event a ...
- js 获取小数点位数方法及 字符串与数字之间相互转换方法
1.获取小数点位数方法 a. 使用 js 中 subsrting,indexOf,parseFloat三个函数,代码如下: var s = "22.127456" ;//s 为 字 ...
- 自定义响应结构 Json格式转换 工具类
import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterx ...
- oracle 块的学习——有定义和执行部分的块
declare --定义变量 v_ename varchar2(5); begin --执行部分 select ename from emp where empno=&no; --在控制台显示 ...
- [课程设计]Scrum团队分工及明确任务1.0 ----多鱼点餐
[课程设计]Scrum团队分工及明确任务1.0 ----多鱼点餐 一.开发背景 多鱼点餐系统是一套比较系统化的针对餐厅点餐服务的产品,从顾客进入餐厅点餐到用餐结束再到最后的结账买单,需要全面的.高效的 ...