在C#中比较两个对象的相等性

3
这是一个基础类型的问题,请原谅我的业余水平。
第一种情况:
Employee _emp1 = new Employee();
Employee _emp2 = _emp1;
_emp1.Equals(_emp2) ==> RETURNS a True !!

案例2:

Employee _emp1 = new Employee();
Employee _emp2 = new Employee();
_emp1.Equals(_emp2) ==> RETURNS a False !!

能否解释一下上面的比较方法以及从内存映射和分配的角度来说明原因?

3
你惊讶于案例1吗?你有C++背景吗? - Damien_The_Unbeliever
@Damien_The_Unbeliever 我想是这样,Bingo! - Cris
2
-1 抱歉,但我认为SO不是这种水平问题的适当场所。这种事情在MSDN和博客中已经被反复讨论过了。 - DeanOC
这与面向对象编程有什么关系?建议您重新标记此内容。 - PeteH
7个回答

9

简单来说,默认比较器比较对象实例。

  • 在第一个示例中,_emp1_emp2 都指向 Employee 的同一实例,因此 Equals 返回 true。

  • 在第二个示例中,您创建了两个不同的 Employee 对象,_emp1_emp2 是两个不同的对象。因此,Equals 返回 false。


请注意,对于引用类型,复制构造函数 不会被隐式调用。如果这样做:

Employee _emp1 = new Employee();
Employee _emp2 = new Employee(_emp1); //or _emp1.Clone() if that is implemented

如果使用默认比较器,则Equals会返回false,因为它们是两个不同的对象。

还要注意的是,对于值类型,这种行为是不同的。


此外,如果你(应该)重写EqualsCompareTo的默认行为,那么上述所有内容都将无关紧要。一个标准的技巧可能是(假设有一点):

public bool Equals(object rhs)
{
    var rhsEmployee = rhs as Employee;
    if(rhsEmployee == null) return false;

    return this.Equals(rhsEmployee);
}

public bool Equals(Employee rhs)
{
     return this.EmployeeId == rhs.EmployeeId;
}

更多阅读:


在你的第一个要点中,你的意思是:_emp1和_emp2都指向同一内存位置。而在第二个要点中,_emp1和_emp2指向两个不同的内存位置。这与堆栈、堆有什么关系吗? - LetsKickSomeAss in .net
1
@LetsKickSomeAssin.net 语义上是相同的,没错。然而,在托管世界中,我们倾向于避免直接谈论内存,因为我们通常没有直接控制它。但是,底层确实在检查 Object.ReferenceEquals,它比较了两个指针值。 - lc.
这段代码无法编译,因为编译器拒绝将 null 转换为 bool。如果另一个实例不是 Employee,则 Equals 应该返回 false - Nuffin
@Nuffin 谢谢。我指的是“false”。 - lc.
@Nuffin 再次感谢您的编辑。我想我当时有点累了... :( - lc.

4
Employee _emp1 = new Employee();

每当你使用new Employee()时,堆和栈中都会分配新的内存。

这意味着_emp1是指向堆内存中1212位置的值。

现在你有第二个语句:

Employee _emp2 = new Employee();

因此,堆中的新值 _emp2 为 1414。

这就是为什么在这里 _emp1.Equals(_emp2) 返回false的原因。

当你说

_emp1 = _emp2

您正在两者中分配相同的值。

2

"这个苹果属于乔。这个梨也属于同一个人。这个苹果的主人和这个梨的主人是同一个人吗?是的。"

"这个苹果属于苏珊。这个梨也属于苏珊。这个苹果的主人和这个梨的主人是同一个人吗?不是,他们只是碰巧都叫苏珊。"


1

无法将两个不同的员工实例等同起来,你需要一种方法来判断它们是否相等,因为它们是不同的实例。在第一种情况下,这些实例是相同的,_emp2 等于 _emp1。你可以通过实现 IEquatable<T> 接口来实现这一点。

public class Employee : IEquatable<Employee>
{
  public int Id { get; set; }

  public bool Equals(Employee other)
  {
    return other.Id == Id;
  } 
}

你可以这样做。
Employee e = new Employee() { Id = 1 };
Employee e2 = new Employee() { Id = 1 };
//Returns true
bool b = e.Equals(e2);

1
你应该创建自己的Equals方法。默认情况下,Equals是从Object类调用的,它基本上检查这两个引用是否指向一个对象(即调用Object.ReferenceEqual(object, object))。

1
如果Employee没有实现自己的.Equals()方法,那么它正在使用Object.Equals(),这仅比较引用。在情况1中,当分配时,您的两个引用将相等。
如果您想通过其内部属性比较Employee对象,则应实现自己的.Equals()方法,如果所有这些属性值匹配,则返回true,否则返回false。

1
当你写Employee _emp1时,你正在分配所需的内存来存储指向另一个将包含Employee实例的内存块的指针。 new Employee();分配一个新的内存块,并用Employee实例填充它,然后返回这个内存块的地址(指针)。就像1234567这样。因此,在执行Employee _emp1 = new Employee();之后,你的_emp1等于1234567,而指向1234567的内存中包含了你的Employee。
然后你执行Employee _emp2 = _emp1;,结果是另一个能够包含指向包含Employee实例的内存块的地址的内存块(_emp2)也等于1234567。这意味着当你执行_emp1.Equals(_emp2)时,结果为true,因为两个变量都指向同一个内存块。
在第二种情况下,另一个 Employee 实例被创建并放置在不同的内存空间中(例如 7654321),并将该地址分配给 _emp2,因此与 _emp1 不同。

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