我有以下代码:
object val1 = 1;
object val2 = 1;
bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true
这是怎么回事?修复它的唯一方法是使用.Equals() 方法吗?
==
是静态的而不是虚拟的,所以行为由静态类型而不是运行时类型确定。引用类型对象上 ==
的默认实现是比较引用(尽管类型可以实现不同的行为,例如 string
)。你有两个不同的对象,它们没有相同的引用,因此 ==
返回false。value1
的运行时类型是Int32
,因此你最终会调用Int32.Equals。从.NET Reflector上可以看到它的实现如下:public override bool Equals(object obj)
{
return ((obj is int) && (this == ((int) obj)));
}
换句话说,它检查参数是否为int
类型,如果是,则强制转换并使用为int
定义的==
。这比较整数的值。
修复这个问题的唯一方法是使用.Equals()方法吗?
另一种方法是将对象转换为int
,然后像Int32.Equals
实现一样使用==
。
是的。 ==
检查引用相等性。在需要比较内容时使用 Equals
。
如果您对对象的情况感到困惑,那么当您将整数(值类型)设置为对象变量时,会发生一种称为装箱的操作。此操作将值类型包装到对象中,并将其放置在堆上并返回一个引用。这个过程会进行两次,导致引用不同(尽管值相同)。
==
检查两个对象是否是相同的。它们不是相同的。它们表示相同的数字,但存储在内存中的不同位置。
这就像比较两个苹果。两个都是苹果并且看起来一样,但它们是不同的对象。
如果两个对象指向内存中的同一空间,则它们相等。
val1 == val1; //Equals true
正如tc所指出的,您可以进行运算符重载。
public static bool operator ==(Object a, Object b)
这样操作符==
的行为将由此方法定义。
当你重载==
时,你也应该重载操作符!=
。
如果您不是使用 object
而是自定义类,您可以重写 == 和 != 运算符,并且可能应该实现 IEqualityComparer<T>
接口。
public static bool operator ==(MyType left, MyType right)
{
//code here, don't forget about NULLS when writing comparison code!!!
}
public static bool operator !=(MyType left, MyType right)
{
return !(left == right);
}
public bool Equals(MyType x, MyType y)
{
return (x == y);
}
public int GetHashCode(MyType obj)
{
return base.GetHashCode();
}
你的代码框中的CIL装箱了两个整数并比较了由装箱后得到的两个对象(==)。 这种比较是通过引用进行的。
.locals init ([0] object val1,
[1] object val2,
[2] bool result1,
[3] bool result2)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldc.i4.1
IL_0009: box [mscorlib]System.Int32
IL_000e: stloc.1
IL_000f: ldloc.0
IL_0010: ldloc.1
IL_0011: ceq
IL_0013: stloc.2
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: callvirt instance bool [mscorlib]System.Object::Equals(object)
IL_001b: stloc.3
对于.Equals,它调用Object.Equals,该方法调用Int32.Equals(在Object上进行虚拟方法调用):
public override bool Equals(object obj)
{
return ((obj is int) && (this == ((int) obj)));
}
这将转换为整数并将其作为整数进行比较,即值类型比较。
object.Equals(object,object)
的静态方法,它首先尝试使用==
运算符比较对象,如果两个参数都不为 null,则再尝试使用object.Equals(object)
方法。我建议使用它是因为在调用object.Equals(object,object)
时无需检查 null,但你需要在调用object.Equals(object)
之前检查 null。 - Dr. Wily's Apprentice