两个相等的.NET对象却显示它们不相等

17

我有以下代码:

object val1 = 1;
object val2 = 1;

bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true

这是怎么回事?修复它的唯一方法是使用.Equals() 方法吗?


它们声称相等,但是两个不同的实例。 - Rune FS
1
老兄,== 和 .Equals 执行两种不同的操作。== 运算符检查 val1 和 val2 是否占用相同的内存空间(引用)。.Equals 检查内容是否相等。 - Icemanind
6
你还可以使用object.Equals(object,object)的静态方法,它首先尝试使用 == 运算符比较对象,如果两个参数都不为 null,则再尝试使用object.Equals(object)方法。我建议使用它是因为在调用object.Equals(object,object)时无需检查 null,但你需要在调用object.Equals(object)之前检查 null。 - Dr. Wily's Apprentice
7个回答

35
运算符 == 是静态的而不是虚拟的,所以行为由静态类型而不是运行时类型确定。引用类型对象上 == 的默认实现是比较引用(尽管类型可以实现不同的行为,例如 string )。你有两个不同的对象,它们没有相同的引用,因此 == 返回false。
如你所指出的,解决方案是使用Equals。Equals是一个虚方法。由于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实现一样使用==


这似乎是唯一正确的答案(或者至少我非常确定你可以在字符串上使用==并且它会按预期工作)。 - tc.
1
好的,我不明白为什么在这里使用Equals方法。根据文档http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx所述,“*Equals*的默认实现对于引用类型支持引用相等性,对于值类型支持位相等性。引用相等性意味着被比较的对象引用指向同一个对象。” - John C
@John C:好问题。我的更新答案是否更清晰? - Mark Byers
是的,谢谢,现在我明白了。我想对于您自己定义的类,您需要提供自己的Equals定义。 - John C

10

是的。 == 检查引用相等性。在需要比较内容时使用 Equals

如果您对对象的情况感到困惑,那么当您将整数(值类型)设置为对象变量时,会发生一种称为装箱的操作。此操作将值类型包装到对象中,并将其放置在堆上并返回一个引用。这个过程会进行两次,导致引用不同(尽管值相同)。


2

==检查两个对象是否是相同的。它们不是相同的。它们表示相同的数字,但存储在内存中的不同位置。

这就像比较两个苹果。两个都是苹果并且看起来一样,但它们是不同的对象。


1
这是因为当你将它们转换为对象时,它们被“转换”为 int 值的引用。而这两个引用并不相等。 但 equals 方法比较的是引用值而不是引用本身所指向的值。

0

如果两个对象指向内存中的同一空间,则它们相等。

val1 == val1; //Equals true

正如tc所指出的,您可以进行运算符重载。

public static bool operator ==(Object a, Object b)

这样操作符==的行为将由此方法定义。

当你重载==时,你也应该重载操作符!=


1
除非有运算符重载。 - tc.

0

如果您不是使用 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();
}

0

你的代码框中的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)));
}

这将转换为整数并将其作为整数进行比较,即值类型比较。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接