不管在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方法的定义为

  1. // System.Collections.Generic.List<T>
  2. /// <summary>Determines whether an element is in the <see cref="T:System.Collections.Generic.List`1" />.</summary>
  3. /// <returns>true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.List`1" />; otherwise, false.</returns>
  4. /// <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>
  5. [__DynamicallyInvokable]
  6. public bool Contains(T item)
  7. {
  8. if (item == null)
  9. {
  10. for (int i = ; i < this._size; i++)
  11. {
  12. if (this._items[i] == null)
  13. {
  14. return true;
  15. }
  16. }
  17. return false;
  18. }
  19. EqualityComparer<T> @default = EqualityComparer<T>.Default;
  20. for (int j = ; j < this._size; j++)
  21. {
  22. if (@default.Equals(this._items[j], item))
  23. {
  24. return true;
  25. }
  26. }
  27. return false;
  28. }

可以看到,使用了默认相等比较器的方法Equals:EqualityComparer,看一下其定义

http://msdn.microsoft.com/zh-cn/library/ms224763(v=vs.110).aspx

  1. public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>

这两个接口只有两个方法,Equals和GetHashCode,但是EqualityComparer是一个抽象类,它实现了IEqualityComparer接口的两个方法且定义为私有方法,却把IEqualityComparer<T>接口的两个方法实现为了抽象方法。

那么因为@default.Equals调用的是IEqualityComparer<T>接口的方法,所以我们要知道Equals的实现方式,关键是在Default的获取上,通过它才可以看到Equals的定义,看一下Default的定义

  1. public static EqualityComparer<T> Default
  2. {
  3. get
  4. {
  5. EqualityComparer<T> equalityComparer = EqualityComparer<T>.defaultComparer;
  6. if (equalityComparer == null)
  7. {
  8. equalityComparer = EqualityComparer<T>.CreateComparer();
  9. EqualityComparer<T>.defaultComparer = equalityComparer;
  10. }
  11. return equalityComparer;
  12. }
  13. }

这里边defaultComparer的定义:(todo volatile 修饰符的定义

  1. private static volatile EqualityComparer<T> defaultComparer;

我们暂时当它是null的,那么就会调用私有方法CreateComparer了。

  1. private static EqualityComparer<T> CreateComparer()
  2. {
  3. RuntimeType runtimeType = (RuntimeType)typeof(T);
  4. if (runtimeType == typeof(byte))
  5. {
  6. return (EqualityComparer<T>)new ByteEqualityComparer();
  7. }
  8. if (typeof(IEquatable<T>).IsAssignableFrom(runtimeType))
  9. {
  10. return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), runtimeType);
  11. }
  12. if (runtimeType.IsGenericType && runtimeType.GetGenericTypeDefinition() == typeof(Nullable<>))
  13. {
  14. RuntimeType runtimeType2 = (RuntimeType)runtimeType.GetGenericArguments()[];
  15. if (typeof(IEquatable<>).MakeGenericType(new Type[]
  16. {
  17. runtimeType2
  18. }).IsAssignableFrom(runtimeType2))
  19. {
  20. return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), runtimeType2);
  21. }
  22. }
  23. if (runtimeType.IsEnum && Enum.GetUnderlyingType(runtimeType) == typeof(int))
  24. {
  25. return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), runtimeType);
  26. }
  27. return new ObjectEqualityComparer<T>();
  28. }

在这里,根据不同的运行时类型,实例化不同的EqualityComparer子类。在此只看最后一个return(todo 其他子类),ObjectEqualityComparer:这是一个internal的类,我们是用不了的

  1. internal class ObjectEqualityComparer<T> : EqualityComparer<T>

然后我们可以找到Equals,这里会有两个

  1. public override bool Equals(T x, T y)
  2. {
  3. if (x != null)
  4. {
  5. return y != null && x.Equals(y);
  6. }
  7. return y == null;
  8. }
  9. public override bool Equals(object obj)
  10. {
  11. ObjectEqualityComparer<T> objectEqualityComparer = obj as ObjectEqualityComparer<T>;
  12. return objectEqualityComparer != null;
  13. }

我们用到的是第一个(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

追下去后:

  1. public virtual bool Equals(object obj)
  2. {
  3. return RuntimeHelpers.Equals(this, obj);
  4. }
  1. [SecuritySafeCritical]
  2. [MethodImpl(MethodImplOptions.InternalCall)]
  3. 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方法

  1. public bool Contains(T item)
  2. {
  3. if (this.m_buckets != null)
  4. {
  5. int num = this.InternalGetHashCode(item);
  6. for (int i = this.m_buckets[num % this.m_buckets.Length] - ; i >= ; i = this.m_slots[i].next)
  7. {
  8. if (this.m_slots[i].hashCode == num && this.m_comparer.Equals(this.m_slots[i].value, item))
  9. {
  10. return true;
  11. }
  12. }
  13. }
  14. return false;
  15. }

看了下,m_comparer是IEqualityComparer<T>类型的,所以这里的Equals和上边是一样的。除了Equals,hashset还要比较hashcode,这是比较特别的地方。

contains 方法的更多相关文章

  1. javaSE27天复习总结

    JAVA学习总结    2 第一天    2 1:计算机概述(了解)    2 (1)计算机    2 (2)计算机硬件    2 (3)计算机软件    2 (4)软件开发(理解)    2 (5) ...

  2. mapreduce多文件输出的两方法

    mapreduce多文件输出的两方法   package duogemap;   import java.io.IOException;   import org.apache.hadoop.conf ...

  3. 【.net 深呼吸】细说CodeDom(6):方法参数

    本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...

  4. IE6、7下html标签间存在空白符,导致渲染后占用多余空白位置的原因及解决方法

    直接上图:原因:该div包含的内容是靠后台进行print操作,输出的.如果没有输出任何内容,浏览器会默认给该空白区域添加空白符.在IE6.7下,浏览器解析渲染时,会认为空白符也是占位置的,默认其具有字 ...

  5. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  6. [C#] C# 基础回顾 - 匿名方法

    C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...

  7. ArcGIS 10.0紧凑型切片读写方法

    首先介绍一下ArcGIS10.0的缓存机制: 切片方案 切片方案包括缓存的比例级别.切片尺寸和切片原点.这些属性定义缓存边界的存在位置,在某些客户端中叠加缓存时匹配这些属性十分重要.图像格式和抗锯齿等 ...

  8. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

  9. JS 判断数据类型的三种方法

    说到数据类型,我们先理一下JavaScript中常见的几种数据类型: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Functi ...

  10. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

随机推荐

  1. 附加数据库失败,操作系统错误 5:"5(拒绝访问。)"的解决办法

    无法打开物理文件 XXX.mdf".操作系统错误 5:"5(拒绝访问.)". (Microsoft SQL Server,错误: 5120)   找到xxx.MDF与xx ...

  2. Objective-C汇总

    Objective  C(20世纪80年代初) 一.OC语言概述 .1985年,Steve  Jobs成立了NeXT公司 .1996年,12月20日,苹果公司宣布收购了NeXT  softwar ...

  3. vs下 qt源码调试

    1.下载qt源码,我下载的是4.7.1版本 2.vs安装qt插件qt-add-in 3.进入qt根目录,打开configure文件,找到 QT_DEFAULT_BUILD_PARTS="li ...

  4. 轮播效果(margin-left/top)移动

    HTML代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  5. linux c网络编程之函数

    1. struct protoent *protocol=getprotobyname(char *p); 功能:通过协议名获取协议类型信息 解释:p为字符串指针,指向一个协议名,如icmp,stru ...

  6. java可变参数

    Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.注意:可变参数必须位于最后一项.当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持 ...

  7. js的事件委托

    什么是事件委托:通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事 ...

  8. 转载《Android-TabHost 选项卡功能用法详解》

    一. TabHost介绍 TabHost组件可以在界面中存放多个选项卡, 很多软件都使用了改组件进行设计; 1. TabHost常用组件 TabWidget : 该组件就是TabHost标签页中上部 ...

  9. 转:android异步任务设计思详解(AsyncTask)

    这里说有设计思想是我根据查看Android源代码提炼出来的代码逻辑,所以不会跟Google工程师的原始设计思想100%符合(也有可能是0%),但是本文一定可以帮助你理解AsyncTask,也可能有一些 ...

  10. commonJS

    摘自阮一峰博客:http://javascript.ruanyifeng.com/nodejs/module.html 目录 概述 module对象 module.exports属性 exports变 ...