MagicbehindValueType.Equals
在《有效的C#》一书中,比尔·瓦格纳写道:“当你创建一个值类型时,你必须重写value type。等于()”。他主要考虑的是性能问题。在ValueType的默认实现中。Equals函数,它的所有成员变量都需要通过反射枚举,开销比较大。
考试提示:公共语言运行库专门针对“简单”值类型进行了优化。让我们看一看。
这是ValueType的实现。rotor中的Equals函数(" clr \ src \ bcl \ system \ value type . cs "):
bool Equals(object obj)
{
//比较类型
//如果这个对象中没有GC引用我们可以避免反射
//做一个快速memcmp
if(CanCompareBits(this))
{
return FastEqualsCheck(this,obj);
}
//使用反射进行比较
}
这里最重要的两个函数是“CanCompareBits”和“FastEqualsCheck”。都标有“[MethodImpl (MethodOptions。InternalCall)]"属性,该属性指示它们的实现在公共语言运行库内部。
通过浏览rotor的源代码,Examda表示这两个函数的实现可以在“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函数的其他值类型,上述优化可能会导致错误的结果。
这是公共语言运行时中的一个错误,但它也告诉我们您为值类型重写了Equals函数。
0条评论