Magic behind ValueType.Equals
来源:互联网 发布:mac怎么用u盘装系统 编辑:程序博客网 时间:2024/06/07 19:17
原文:http://blogs.msdn.com/xiangfan/archive/2008/09/01/magic-behind-valuetype-equals.aspx
在"Effective C#"一书中,Bill Wagner写到:“在你创建值类型的时候,一定要重写ValueType.Equals()”。他主要考虑的是性能问题,在ValueType.Equals函数的默认实现里,需要使用反射枚举它所有的成员变量,开销是比较大的。
实际上,公共语言运行时针对“简单”值类型作了特殊的优化。让我们来瞧一瞧。
这是rotor中ValueType.Equals函数的实现("clr/src/bcl/system/valuetype.cs"):
bool Equals(object obj)
{
//Compare type
//if there are no GC references in this object we can avoid reflection
//and do a fast memcmp
if (CanCompareBits(this))
{
return FastEqualsCheck(this, obj);
}
//Compare using reflection
}
这里最重要的两个函数"CanCompareBits"和"FastEqualsCheck"。它们都被标记了"[MethodImpl(MethodImplOptions.InternalCall)]"属性,说明它们的实现是在公共语言运行时的内部的。
通过浏览rotor的源代码,你可以在"clr/src/vm/comutilnative.cpp"中找到这两个函数的实现。
CanCompareBits函数的注释写到:“如果值类型不包含指针或者没有填充,将返回true”。而FastEqualsCheck函数使用"memcmp"进行快速的二进制比较。
你会说,这个优化实现很不错啊,我的值类型很简单,不用自己重写Equals函数了。但是请等一下,你有没有发现CanCompareBits的问题?
问题是注释中提到的条件并不能保证二进制的比较能够得到正确的结果。
设想一下,你有一个值类型A,它只有一个float类型的成员f。你定义了两个A的对象a和b,a.f=+0.0,b.f=-0.0。从逻辑上来讲,它们应该是相等的,但是它们的二进制表示却是不同的。因此没有优化的代码将返回true,而优化之后的版本将返回false。
类似的,如果你的值类型中包含了其它重写了Equals函数的值类型,那么上述的优化都可能导致错误的结果。
这是公共语言运行时的一个bug,但是它也告诉我们,你最好为你的值类型重写Equals函数 :-)
- Magic behind ValueType.Equals
- The magic behind configure, make, make install
- ValueType.Equals(null)的底层实现及CLR虚拟机对其结构支持
- ValueType下的Equals代码(.net1.x和4.0缺2.0)
- 【magic】
- magic
- Magic
- magic
- code-behind
- 在C#函数的参数使用valuetype
- equals
- Equals
- Equals
- equals
- equals
- Equals
- equals
- equals()
- CMPP3与CMPP2的区别
- 欢迎大家访问
- Hibernate主键生成方式 Key Generator
- 如何制作Java可执行程序以及安装程序(补上了图片)
- mips汇编打印 hello world
- Magic behind ValueType.Equals
- 排序算法 通用化设计
- 开源EntLib.com Blog 博客平台系列文章汇集
- Repeater自定义分页(1)
- ORACLE 部分命令学习笔记
- Repeater自定义分页排序(2)
- Repeater自定义分页 + 排序 + 全选删除(3)
- 使用JavaScript在网页中弹出提示信息
- 打开DXVA(显卡硬解码H.264与VC-1)已如此简单