不管在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 方法的更多相关文章

  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. Efficiency Office Toolkit Clients

    <?xml version="1.0" encoding="utf-8" standalone="yes"?><Ftp&g ...

  2. LESS用法·

    CSS 彻底改变了 Web 页面的设计,但 CSS 仍然是静态的,而且在其句法发展方面受到限制.这些限制是有目的且合乎情理的,鼓励广泛加以实现.但开发人员和设计人员常常发现 CSS 使用起来很单调乏味 ...

  3. golang http服务器跨域问题解决

    func main() { openHttpListen() } func openHttpListen() { http.HandleFunc("/", receiveClien ...

  4. RNN 入门学习资料整理

    建议按序阅读 1. RNN的一些简单概念介绍 A guide to recurrent neural networks and backpropagation Deep learning:四十九(RN ...

  5. java虚拟机判断对象是否存活的方式

    引用计数算法:   给对象添加一个引用计数器,每当有地方应用时,计数器值就加一,当引用失效时,程序计数器就减一,只要引用计数器的值为零时,就表示对象不可能再被引用,例如微软的 component ob ...

  6. libevent之丢失header问题

    本文为原创,转载请注明:http://www.cnblogs.com/gistao/ 背景 分享一个hhvm使用http server方式来处理请求的问题及对应的patch.hhvm3+版本支持fas ...

  7. Python 中的虚拟环境

    检查系统是否安装了virtualenv: $ virtualenv --version 创建虚拟环境venv(名字可以随便取,一般为venv): $ virtualenv venv 使用虚拟环境ven ...

  8. 开始写Effective系列总结一些前端的心得

    确实是没有时间整理以及总结和发表自己的感慨.难得中秋银行的事情搞完了自己清闲3天,是时候总结一下从大公司做.NET PC 端网站的开发到现在做移动互联网的银行及政府微信公众号的开发的感触.当时自己的选 ...

  9. js 测试

    今天js测试题目: 被基础题目虐暴......惨不忍睹 1. var num = 2; switch(num){ case 1: console.log("1"); case 2: ...

  10. Sequential List

    Sequential ListSequential list storage structure:#define LIST_INIT_SIZE 20 #define LIST_INCREASE 10t ...