跟小静读CLR via C#(04) 本是同根生

跟小静读CLR via C#(04)- 本是同根生

说起.NET中的类,本是同根生,一点不为过。因为CLR要求所有类都要继承自System.Object。所有对象都必须提供一组通用操作,包括对象的等值性唯一性散列码以及克隆



一、等值性——Equals()方法

有时候我们需要比较两个对象是否相等,比如在一个ArrayList中进行排序查找等操作时。

System.Object提供了Equals()虚方法:

class Object

{

public virtual Boolean Equals(object o)

{

if (this == o) return true;

else return false;

}

}

这种判断方式非常简单:直接比较是两个引用是否指向的是同一对象。但这样比较是不确切的。所以我们需要重写该方法,提供更合适的实现方式。

重写时Equals()四大原则?我们在离散数学中好像学过这个呀:

  • 自反。即x.Equals(x)必须为true。
  • 对称。即x.Equals(y)和y.Equals(x)必须返回同样的值。
  • 可传递。即如果x.Equals(y)和y.Equals(z)都返回true,则x.Equals(z)也返回true。
  • 前后一致。如果两个对象的值没变,那么多次比较的值都应该是相同的。

重写思路

  • 1. 如果参数obj为null,返回false。      因为在非静态方法中,使用this表示的当前对象肯定不是Null。
  • 2. 如果this和obj参数指向同一实例对象,返回true。    这样省略字段比对过程,提高性能。
  • 3. 如果this 和obj参数指向的对象类型不同,则返回false。
  • 4. 比较this和obj中每个实例字段,如果字段不相等则返回false。
  • 5. 调用基类的Equals方法,如果调用结果为false,则返回false;
  • 6. 至此,才能返回true。

 

二、惟一性——ReferenceEquals() 方法

惟一性指两个引用指向同一对象。一旦我们的类重写了Ojbect的Equals方法,我们就不能用它来检测唯一性了。Object提供了另一个静态方法ReferenceEquals()

public class Object {

public static Boolean ReferenceEquals(Object objA, Object objB) {

return (objA == objB);

}

}

但是我们尽量不要在C#中用==操作符来判断唯一性,除非两参数都为Object类型。因为有可能其中一个参数类型会重写==操作符,使他产生了其他语义。

实例体验?

class Animal { };

static void Main(string[] args)
        {
            Animal a1 = new Animal();
            Animal a2 = a1;
            Console.WriteLine(Object.ReferenceEquals(a1, a2));                //true,指向同一对象
            a2 = new Animal();
            Console.WriteLine(Object.ReferenceEquals(a1, a2));                //false,a2重新指向新对象
            int number = 100;
            Console.WriteLine(Object.ReferenceEquals(number, number));//false,值类型Number两次装箱到不同的对象中
            Console.Read();
        }

三、散列码——GetHashCode() 方法

System.Object提供了虚方法GetHashCode()从一个对象上得到Int32的散列码。该方法返回的是在整个应用程序域中保证惟一的值,该值在对象整个生存周期内都不会改变。

如果我们重写了类的Equals()方法,那么我们最好也重写GetHashCode()方法,否则编译器可能会产生警告信息。因为System.Collections.Hashtable类要求两个相等的对象具有相同的散列值。

四、克隆——ICloneable接口

如果一个类允许实例被拷贝,则继承ICloneable接口。

Public interface ICloneable{ object Clone();}

浅拷贝?

当对象的字段值被拷贝时,字段引用的对象不会被拷贝。实现时可以调用Object的MemberwiseClone方法即可。

深拷贝?

对象实例中字段引用的对象也进行拷贝。深拷贝后,新创建的对象和原对象没有任何公用的东西,改变一个对象时也不会影响另外一个。

原文地址:https://www.cnblogs.com/janes/p/2100985.html