平等检查的5种方式.net ..为什么?和哪些使用?

时间:2010-07-07 04:41:30

标签: c# .net

在学习.net(通过c#)时,我找到了5种方法来检查对象之间的相等性。

  1. ReferenceEquals()方法。
  2. 虚拟Equals()方法。 (System.Object的)
  3. 静态Equals()方法。
  4. 来自IEquatable接口的Equals方法。
  5. 比较运算符==。
  6. 我的问题是:

    1. 为什么有这么多Equals()方法和比较运算符?
    2. 使用虚拟Equals()或IEquatable的Equals()sholud中的哪一个...(比如说我们使用自己的集合类)

4 个答案:

答案 0 :(得分:29)

  

ReferenceEquals()方法。

这用于测试两个给定变量是否指向同一个对象(符号引用)。它实际上相当于((object)a) == ((object)b)。如果覆盖比较运算符(==),则ReferenceEquals会保留一种访问默认行为的方法。

然而,如果您正在处理值类型(例如结构),那么这个will always return false。这是因为比较框每个值都为新对象的类型,所以引用自然不会相等。


  

虚拟Equals()方法。 (System.Object的)

这是在语义上比较两个对象(任何类型)的默认方式。每个班级都会根据他们的选择覆盖。默认情况下,它等同于CLR调用(InternalEquals),它基本上比较了内存​​引用。

注意,如果Equals()的两个对象返回true,则每个GetHashCode() obj1.GetHashCode() == obj2.GetHashCode()都返回Equals()。但是,如果两个对象的哈希码值相等(即Equals),则表示GetHashCode为真。

您的类通常应实现==Equals作为区分类实例的方法,并且如果它是值类型,则必须实现此操作或ValueType.Equals()运算符(理想情况下都是)。

注意,对于值类型,默认return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)))行为是Object的行为,如果您查看Reflector(或读取must be equal),则使用反射来比较两个值实例的成员


  

静态Equals()方法。

这相当于Equals,其中每种类型都转换为a.Equals(b)进行测试。我的测试显示忽略了重载的比较运算符,但如果对象不为null且不是相同的引用,则将使用object.Equals(a, b)方法。因此,((object)a) == ((object)b)不一定等于Equals(对于Equals或a或b为空的情况。)


  

来自IEquatable接口的Equals方法。

IEquatable提供了一种方法,可以专门处理与同一个类的实例的比较。说了string方法the MSDN description

  

如果你实施Equals,你应该   也覆盖基类   的实现   Object.Equals(Object)和GetHashCode   这样他们的行为是一致的   与IEquatable.Equals的那个   方法

should be handling the behaviour the same way

  

处理对象的可能性   类的存储将存储在数组中   或者是一个通用的集合对象,它是   实现IEquatable是一个好主意   这样物体就可以轻松实现   识别和操纵。


  

比较运算符==

当两个对象都是同一个引用时,默认情况下,比较运算符返回true。

Nevertheless you should implement IEquatable覆盖比较运算符,除非您处理is not recommended(在这种情况下建议使用!=方法)或通常不可变的引用类型按值进行比较(例如requires a matching operator '!=' to also be defined)。始终同时实施{{1}}(事实上,如果我不这样做,我会收到{{1}}错误。)


<强>资源:

答案 1 :(得分:27)

1 - 引用等于检查两个引用类型变量(类,而不是结构)是否被引用到同一个内存地址。

2 - 虚拟Equals()方法检查两个对象是否相同。让我们说你有这个课程:

class TestClass{
    public int Property1{get;set}
    public int Property2{get;set}

    public override bool Equals(object obj)
    {
        if (obj.GetType() != typeof(TestClass))
            return false;

        var convertedObj = (TestClass)obj;

        return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
    }
}

并从该类实例化2个对象:

var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}

虽然这两个对象不是TestClass的同一个实例,但对o1.Equals(o2)的调用将返回true。

3 - 静态Equals方法用于在检查中存在空值时处理问题。 想象一下,例如:

TestClass o1 = null;
var o2 = new TestClass{property1 = 1, property2 = 2}

如果您尝试这样做:

o1.Equals(o2);

你会得到一个NullReferenceException,因为o1指向什么都没有。 要解决此问题,请执行以下操作:

的Object.Equals(O1,O2);

此方法准备处理空引用。

4 - IEquatable接口由.Net提供,因此您无需在Equals方法中进行强制转换。 如果编译器发现您已在类中尝试检查相等性的类中实现了接口,则它将使该方法优先于Object.Equals(Object)覆盖。 例如:

class TestClass : IEquatable<TestClass>
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }

    public override bool Equals(object obj)
    {
        if (obj.GetType() != typeof(TestClass))
            return false;

        var convertedObj = (TestClass)obj;

        return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
    }

    #region IEquatable<TestClass> Members

    public bool Equals(TestClass other)
    {
        return (other.Property1 == this.Property1 && other.Property2 == this.Property2);
    }

    #endregion
}

现在,如果我们这样做:

var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
o1.Equals(o2);

被调用的方法是Equals(TestClass),在Equals(Object)之前。

5 - ==运算符通常与ReferenceEquals相同,它检查两个变量是否指向同一个内存地址。 问题是可以覆盖此运算符以执行其他类型的检查。 例如,在字符串中,它会检查两个不同的实例是否相同。

这是更好地理解.Net中的平等性的有用链接:

答案 2 :(得分:1)

每个版本的平等略有不同。

ReferenceEquals测试参考相等性。

默认情况下,

virtual Equals检查类类型的引用相等性和结构类型的值相等性。如果需要,可以覆盖它以不同方式定义相等性;并且应该覆盖值类型。

static Equals只需调用virtual Equals,但也允许null个参数。

IEquatable<T>.Equalsvirtual Equals的通用/类型安全等效项。

operator==旨在与默认的virtual Equals类似,意味着类类型的引用相等(除非该类也覆盖其他运算符)。它也应该被重写为值类型。

如果您编写自己的集合类,请使用IEqualityComparer<T>,默认为EqualityComparer<T>.Default。不要直接使用任何相等比较。

答案 3 :(得分:0)

对于基元,请坚持使用==运算符。

在.NET框架中提供的大多数对象中,您创建的.Equals()方法和==运算符只会检查两个对象是否引用堆上的同一对象。

IEquatable接口的目的是覆盖.Equals()方法,以更改其行为,检查引用相等性以检查值是否相等。 System.String类型是实现此接口的内置.NET对象的示例。

.ReferenceEquals()方法为那些覆盖标准.Equals()方法的开发人员提供了一种方法,可以检查两个对象的引用相等性。