Effective50.Rules06.理解几个等同性判断之间的关系.Note

当我们定义自己的类型时(无论是类还是Struct),应该为类型定义等同性的含义。C#定义了4中不同的函数来判断两个对象是否“相等”。

1.public static bool ReferenceEquals(object left,objec right)

2.public static bool Equals(object left,object right);

3.public virtual bool Equals(object right);

4.public static bool operator ==(MyClas left,MyClass right);

对于前两种静态函数,我们永远都应该重新定义。我们通常创建自己的实例的Equals(),来为类型定义等同的语义。偶尔需要覆盖operator==().

    当然,这4种方法并不是等同性比较的唯一选择。覆盖Equals()方法的类型应该实现IEquatable<T>;实现值语义(value semantics)的类型同时还应该实现IStructurealEquality接口。这意味着有6种方法来表达等同性。

   如果两个类型的变量指向的是同一个对象,我们认为他们是“引用相等”。如果两个值类型变量类型相同,而且包含同样的内容,是“值相等”。

Object.ReferenceEquals(leftObj,rightObj)

    如果两个变量指向同一个对象,也就是他们拥有同样的对象标示(object identity),那么Object.ReferenceEquals(leftobj,rightobj)返回true;无论比较引用类型还是值类型,该方法判断依据都是对象的标示,而不是对象内容。

   Object.ReferenceEquals(,)来判断值类型永远返回false,即使自己跟自己比较,其原因在于装箱,参见条目45.

 

第二,永远不要去重新定义静态函数Object.Equals().当你不知道两个变量运行时类型,可以使用该方法来判断两个对象是否相等。注意,任何类型都是System.Object的实例无论是值类型还是引用类型。

静态Object.Equals()把比较的具体操作委托给具体的类型来做,它的具体实现如下:

        public static new bool Equals(Object left, Object right)
        {
            //Check object identity
            if (object.ReferenceEquals(left, right))
                return true;
            if (object.ReferenceEquals(left, null) || object.ReferenceEquals(right, null))
                return false;
            return left.Equals(right);//最后将比较委托给具体类型
        }

在阐述实例对象的Equals方法前,我们先谈谈等同性在数学方面的几个要点:

    自反性(reflexive)无论a是什么类型,a==a应该返回true;

    对称性(symmetric),意味着等同判断与判断的顺序无关,即,a==b与b==a应该是相同的结果。

    传递性(transitive),a==b且b==c,那么a==c.

Object.Equals()实例函数默认实现与Object.ReferenceEquals()实现完全相同,都是根据对象标示。System.ValueType重写了实例Equals()方法,但是实现效率不高,使用反射,反射有许多缺点,特别是对性能要求比较高的地方,在程序中被频繁调用的功能。对值类型的建议非常简单,都要去覆盖ValueType.Equals()方法

 

对于引用类型,当我们需要更改Equals()语义的时候才需要覆盖该方法。.NET中有许多类都是用值语义而不是引用语义,例如String对象

自定义语义的Object.Equals()需要遵循定义的行为。当你覆盖Equals()时,也要同时为该类实现IEquatable<T>,下面是一个覆盖Syste.Object.Equals()实例方法标准实现模式

 

 

posted @ 2013-03-29 08:59  Lovey  阅读(191)  评论(0编辑  收藏  举报