我在.NET Reflector中徘徊,并注意到对于像“String”这样的引用类型,“==”运算符有一个显式重载:
typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)
返回:“==”运算符的System.Reflection.MethodInfo。
由于它的实施,你不能做这样的事情:
if("hi" == 3) // compiler error, plus code would throw an exception even if it ran)
然而,同样的事情适用于价值类型:
if((int)1 == (float)1.0) // correctly returns true
if((int)1 == (float)1.2) // correctly returns false
我正在试图弄清楚.NET内部如何处理类型转换过程,所以我在.NET Reflector中寻找op_Equality()的实现,但是“int”没有。
typeof(int).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)
返回null。
那么,值类型的“==”运算符的默认实现在哪里? 我希望能够通过反思来调用它:
public bool AreEqual(object x, object y)
{
if(x.GetType().IsValueType && y.GetType().IsValueType)
return x == y; // Incorrect, this calls the "object" equality override
else
...
}
编辑#1:
我尝试了这个,但它不起作用:
(int)1 == (float)1; // returns true
System.ValueType.Equals( (int)1, (float)1 ); // returns false
编辑#2:
也试过这个,但没有爱情:
object x = (int)1;
object y = (float)1.0;
bool b1 = (x == y); // b1 = false
bool b2 = ((ValueType)x).Equals(y); // b2 = false
我相信这个。由于这种类型检查(从.NET Reflector中翻录),ValueType上的.ququals运算符不起作用:
ValueType.Equals(object obj)
{
...
RuntimeType type = (RuntimeType) base.GetType();
RuntimeType type2 = (RuntimeType) obj.GetType();
if (type2 != type)
{
return false;
}
...
答案 0 :(得分:2)
评估(int)1 ==(float)1.0不依赖于任何特殊的==运算符,只依赖于转换规则。
编译器会将其转换为(float)((int)1)==(float)1.0
编辑: 规则指定为on MSDN。
答案 1 :(得分:2)
您正在寻找的是ValueType.Equals
在许多情况下,这只会对值进行逐位比较。在某些情况下,它会使用反射来验证字段。
编辑
您对C#比较值类型以及.Net如何比较值类型感到困惑。 ValueType.Equals是.Net中的一个函数,用于比较具有相同类型的值类型对象。 C#将发出最终调用该函数的代码。但它并没有用“int”和“float”来调用它。相反,它首先将它们转换为一种类型,该类型不会丢失任何值(double)的精度,然后比较生成的double值。这就是你看到行为上的差异的原因。
答案 2 :(得分:2)
==
op_Equality
对于值类型的默认实现在哪里?
值类型没有默认==
。尝试编写自己的值类型
struct JustAnotherValueType
{
public readonly int Field;
public JustAnotherValueType(int f) { Field = f; }
}
制作您的类型的两个值x
和y
。尝试用x == y
跟他们说。它不会编译。你可以说
(object)x == (object)y
但是这将在x
(让我们称之为方框1)和拳击y
(方框2)上执行装箱,然后在两个方框上执行参考比较。因此它总是会返回false。因此它没用,这就是为什么在==(object x, object y)
之间使用==
时不会自动选择重载JustAnotherValueType
的原因。
那么int
和float
会发生什么?您可以将它们与C#中的==
进行比较,但它们没有op_Equality
方法?!解释是这些重载由 the C# Language Specification 定义。请参阅整数比较运算符和浮点运算比较运算符部分。
事实上,虽然这些运算符不作为.NET结构的成员存在,但C#语言规范定义了它们,并且C#编译器必须生成一些有效的IL来模仿它们的行为。
顺便说一下,System.Object
也没有op_Equality
。它也只由C#定义。请参阅引用类型相等运算符部分。请注意,System.Object
具有ReferenceEquals
方法,编译器可能会选择将此==
的重载转换为。另请注意,规范的此部分提供了限制,以便x == y
永远不会对x
或y
执行装箱。
C#规范中未提及的DateTime
,TimeSpan
和Guid
等值类型如何使用==
合法使用?答案是,这些执行拥有op_Equality
成员。
结论:C#语言规范定义了大量==
重载,需要C#的实现,其中一些重载涉及int
和float
以及{{1 }}
备注:虚拟实例方法object
在Equals(object)
中定义,并由所有值类型继承。对于不自行覆盖此方法的结构,使用object
中的override
。它按价值进行比较。因此,对于上面的System.ValueType
和x
,y
可以正常工作。 x.Equals(y)
是一种虚拟实例方法。另一方面,Equals
是一个==
“方法”,基于两个操作数的编译时类型执行重载决策(没有“虚拟分派”)。
答案 3 :(得分:1)
我猜你正在寻找遗传给你的结构的ValueType.Equals(object obj)。它使用反射来比较所有字段。
答案 4 :(得分:1)
My answer另一个问题提供了Rotor的实现。实际代码在CLR中实现为本机代码。
具体做法是:
// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
(void *) (pThisRef+1),
(void *) (pCompareRef+1),
pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0;