在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近在看 高级点的程序员必看的 CLR via C# 书中说解释了 Object.Equals() 方法的实现, 其中具体的实现用的是 == 运算符 ! 以前就对 == 运算符 的具体实现 产生过疑惑 . 它到底对比的什么? 今天刚好手头的东西弄完了,而且还得强制加班中 ! 所以就那今天的加班时间 来认真 来看一下 == 运算符 !
因为是 Object.Equals() 这方法产生的疑问 所以吧这个内部实行帖出来
public static bool Equals(object objA, object objB) { return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))); } Ps objA.Equals方法得解释一下 . objA使用的Equals方法是 类型自己可能会重写 父类的 Equals 的这个方法.
等于到底做了什么? 关于怎么实现的 非常抱歉的说 我并没有找到 == 运算符的具体实现代码. 但是 可以再MSDN 上看到 它到底干了什么. http://msdn.microsoft.com/zh-cn/library/53k8ybth.aspx == 比较字符串的值。 通过MSDN 上的解释 我们可以看到 好像是 它很厉害 能过自动通过类型 进行不同的对比. 其实并未如此 回到我们的更本问题 : == 运算符 对比的到底什么? 如果你了解 栈 和 托管堆 那么你一定知道 数据 字节 一定不是放在 栈 中 就是放在 托管堆 中 所以 == 运算符 对比 不是对比的 栈 中的数据 就是对比的 托管堆中是数据 可以你觉得我说废话了,但是还是要交代清楚: 我们来看一段简单的代码
class Program { static void Main(string[] args) { Class2 s1 = new Class2(); Class2 s2 = new Class2(); Console.WriteLine(s1 == s2 ? "True" : "false"); } } public class Class2 { } 大家猜一下 是 Ture 还是 False 答案是 False ; 想一下 如果是对比的是 托管堆中的话 那么他们都是创建了 该 对象的 "逐层父类" "类型对象指针" "同步快索引" 等 ; 代码中创建的是一样的 那么 托管堆中的数据就是一样的 如果是对比的 托管堆 那么返回就是 true 显然 程序返回的是 False 而且! 值类型 是存放在 栈 中的 托管堆中并没有东西. 所以 对比 只能是对比 栈中的数据.
说了一堆 就是想先解释清楚 == 运算符对比的是 栈 为什么对比是 栈 而不是托管堆! 我喜欢说的详细点 虽然你可以能觉得啰嗦,我也得巧更多的键盘.但是我认为只有写的很详细了 观看的人才会容易理解.
下面做一些 MSDN 上 == 运算符 对比类型的解释
string 类型 重写了 == 运算符 将其使用了 string 类重写的 Equals 方法进行对比; 具体代码段: public static bool Equals(string a, string b) { return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b))); } public static bool operator ==(string a, string b) { return Equals(a, b); } public static bool operator !=(string a, string b) { return !Equals(a, b); } 关键是 EqualsHelper 这个方法
private static unsafe bool EqualsHelper(string strA, string strB) { int length = strA.Length; if (length != strB.Length) { return false; } fixed (char* str = ((char*) strA)) { char* chPtr = str; fixed (char* str2 = ((char*) strB)) { char* chPtr2 = str2; char* chPtr3 = chPtr; char* chPtr4 = chPtr2; while (length >= 12) { if (((*(((long*) chPtr3)) != *(((long*) chPtr4))) || (*(((long*) (chPtr3 + 4))) != *(((long*) (chPtr4 + 4))))) || (*(((long*) (chPtr3 + 8))) != *(((long*) (chPtr4 + 8))))) { break; } chPtr3 += 12; chPtr4 += 12; length -= 12; } while (length > 0) { if (*(((int*) chPtr3)) != *(((int*) chPtr4))) { break; } chPtr3 += 2; chPtr4 += 2; length -= 2; } return (length <= 0); } } } 它将其每个字符串全部取出单个进行对比. 所有 CLR via C# 中 说是对比的 同等性
现在 == 运算符的 问题都解开了疑惑了 那么让我们重新看一下 Object.Equals 这个方法 public static bool Equals(object objA, object objB) { return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))); } 这段代码我们前面就看过 是 Object.Equals 是代码, 让我们再次解释一下
public override bool Equals(object obj) { if (obj == null) { return false; } RuntimeType type = (RuntimeType) base.GetType(); RuntimeType type2 = (RuntimeType) obj.GetType(); if (type2 != type) { return false; } object a = this; if (CanCompareBits(this)) { return FastEqualsCheck(a, obj); } FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); for (int i = 0; i < fields.Length; i++) { object obj3 = ((RtFieldInfo) fields[i]).InternalGetValue(a, false); object obj4 = ((RtFieldInfo) fields[i]).InternalGetValue(obj, false); if (obj3 == null) { if (obj4 != null) { return false; } } else if (!obj3.Equals(obj4)) { return false; } } return true; } 这是具体实现代码 看的很明显 是通过反射获取对象的值 进行对比 也就的对比的相等性 但是 ! 我们经常使用的 一些 .net预定义的类 几乎还会接着重写这个方法 如 int32 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] public override bool Equals(object obj) { return ((obj is int) && (this == ((int) obj))); } [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] public bool Equals(int obj) { return (this == obj); } 代码如上 可以清楚的看到 它并未 获取对比类型Type 搜索所以字段 属性 获取值对比等一系列复杂的 逻辑 就用了 == 运算符进行的对比 为什么 你们自己想去 懒得说了. 系能是一方面 更本原因还是因为预定义的值类型 是栈中存放.
Ps: 写了这么多 观看的你 可以觉得我写的啰啰嗦嗦的, 但我还是认为写的详细点 把 真实的源码贴出来 才能彻底解决所产生的疑惑. 百度上看一眼 人家说的几句话你就能真的明白了嘛? 如有哪里不对 还希望指正! 本人渴望交流 和指点!
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论