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)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...
随机推荐
- 附加数据库失败,操作系统错误 5:"5(拒绝访问。)"的解决办法
无法打开物理文件 XXX.mdf".操作系统错误 5:"5(拒绝访问.)". (Microsoft SQL Server,错误: 5120) 找到xxx.MDF与xx ...
- Objective-C汇总
Objective C(20世纪80年代初) 一.OC语言概述 .1985年,Steve Jobs成立了NeXT公司 .1996年,12月20日,苹果公司宣布收购了NeXT softwar ...
- vs下 qt源码调试
1.下载qt源码,我下载的是4.7.1版本 2.vs安装qt插件qt-add-in 3.进入qt根目录,打开configure文件,找到 QT_DEFAULT_BUILD_PARTS="li ...
- 轮播效果(margin-left/top)移动
HTML代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- linux c网络编程之函数
1. struct protoent *protocol=getprotobyname(char *p); 功能:通过协议名获取协议类型信息 解释:p为字符串指针,指向一个协议名,如icmp,stru ...
- java可变参数
Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.注意:可变参数必须位于最后一项.当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持 ...
- js的事件委托
什么是事件委托:通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事 ...
- 转载《Android-TabHost 选项卡功能用法详解》
一. TabHost介绍 TabHost组件可以在界面中存放多个选项卡, 很多软件都使用了改组件进行设计; 1. TabHost常用组件 TabWidget : 该组件就是TabHost标签页中上部 ...
- 转:android异步任务设计思详解(AsyncTask)
这里说有设计思想是我根据查看Android源代码提炼出来的代码逻辑,所以不会跟Google工程师的原始设计思想100%符合(也有可能是0%),但是本文一定可以帮助你理解AsyncTask,也可能有一些 ...
- commonJS
摘自阮一峰博客:http://javascript.ruanyifeng.com/nodejs/module.html 目录 概述 module对象 module.exports属性 exports变 ...