弗瑞斯达

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

 参考:http://www.cnblogs.com/pursue/articles/1614285.html

 

有时必须比较两个值是否相等。 在某些情况下,您测试的是“值相等性”(也称为“等效性”),意即两个变量包含的值相等。 而在其他情况下,则必须确定两个变量是否引用内存中的同一基础对象。 这种类型的相等性称为“引用相等性”(或“标识”)。

 

1.Object.ReferenceEquals(object objA,object objB)

作用:比较两个引用类型的对象是否是对同一对象的引用,即引用相等性。

(1)先检查objA、objB是否为null,如果仅有一个为null,返回false,如果两个均为null,返回true

(2)如果 objA、objB为值类型,则先进行装箱到不同的对象实例,因此对于两个值类型,无论它们的值是否相等,总返回false;

(3)如果  objA、objB均为字符串,比较的也是字符串的引用,与值无关。但由于c#字符串池的机制使得字符串的比较有些特殊,见下面的补充部分。

补充:

 对多个引用赋值同一个字符串对象,CLR的解决方法更加巧妙。在默认情况下CLR会使用字符串池的机制,CLR启动的时候,在内部创建一个容器,它以键值对的形式存在,键值是字符串对象内容,值是字符串在托管堆上的引用,当一个新的字符串对象创建的时候CLR检查在这些值中是否已经存在这个字符串对象,如果已经存在就返回对应的值,也就是在托管堆中的引用,如果不存在就在这个容器中中开辟空间存放这个字符串,返回在他的引用。
      这里还是用一段代码来说明:
  public void StringPoolTest()
  {
   string str1 = "789";
   string str2 = "789";
   Console.WriteLine(Object.ReferenceEquals(str1 , str2));
   string str3 = "7" + "8" + "9";
   Console.WriteLine(Object.ReferenceEquals(str1, str3));
   char[] chars = new char[] { '7', '8', '9' };
   string str4 = new string(chars);
   Console.WriteLine(object.ReferenceEquals(str1 , str4));
  }
输出结果:

前两次都输出true说明str1和str2都指向同一个堆引用,最后一个输出false是因为它使用new关键字进行内存分配,字符串池机制不起作用。
这里注意string str3 = "7" + "8" + "9";这个语句在正常的情况下只分配了一次内存,这个也是CLR的优化,在这里就没有分配内存了,因为str1这里已经分配好了。

2.object.Equals(object objA,object objB)

作用:比较任意两个CTS对象。

(1)Equals方法对于值类型和引用类型的定义不同,对于值类型,类型相同,并且数值相同(对于struct的每个成员都必须相同)(即按位相等性,二进制表示形式),则Equals()返回 true,否则返回false;而对于非字符串的引用类型,默认的行为与ReferenceEquals()的行为相同,仅有两个对象指向同一个引用时才返回true;但对于string这个特殊的引用类型来说, Equals 比较的是字符串的值,而非引用,见下面

  输出:

(2)Equals有静态方法和可重写的实例方法两个版本,如果类型的Equals()方法被重写,则调用重写方法,否则调用基类Object的Equals()实例方法。

(3)值得注意的是,如果objA、objB为值类型(测试代码如图1所示),可以看出EqualsReferenceEquals方法一样均先对objA、 objB进行了装箱(IL代码如图2所示),但返回结果却不同,返回结果如图3所示。(原因是Equals方法用于值类型比较时,比较的是值类型的比特值,即按位相等性

图1

图2

图3

 

 

3.==

==是一个可以重载的二元操作符,可以用于比较两个对象是否相等。 
(1)对于内置值类型,==判断的是两个对象的代数值是否相等。它会根据需要自动进行必要的类型转换,并根据两个对象的值是否相等返回true或者false。例如:

Int a = 100; 
Double b =100;

If(a == b) 
Console.WriteLine(“equal supports compare between different types!”);

上面这段程序将会输出: 
equal supports compare between different types!

 注意:由于二进制计算机上浮点算法的不精确性,因此浮点值(doublefloat)的相等比较会出现问题。

 

(2)而对于用户定义的值类型,如果没有重载==操作符,==将是不能够使用的。例如: 
Struct Userstruct1; 
Userstruct1 a; 
Userstruct1 b;

If(a == b) 
Console.WriteLine(“can == reach this far?”)

上面的这段代码是不能够通过编译的。可以通过重载使==作用于用户定义的值类型。

 

(3)对于非字符串的引用类型,== 默认的行为与Equals,ReferenceEquals的行为相同,仅有两个对象指向同一个Reference的时候才返回true。但是.NET Framework中的类很多对==进行了重载,例如String类的==与的行为相同,判断两个字符串的内容是否相等。所以在应用中,对于系统定义的引用类型建议不要使用==操作符,以免程序出现与预期不同的运行结果。

 (4)对于字符串类型来说,== 默认的行为与Equals的行为相同,比较的是字符串的值。

4.比较对象的GetType()和typeof()时,使用==、Object.Equals()和 Object.ReferenceEquals()均可以。

  

posted on 2012-04-22 16:18  弗瑞斯达  阅读(697)  评论(0编辑  收藏  举报