比较类型的VALUE和REFERENCE
我知道有很多方法可以比较C#中的VALUE和REFERENCES,但是当你尝试比较VALUE或REFERENCE时,我仍然对什么类型执行什么感到困惑。
字符串示例:
string str = "hello"; string str2 = "hello"; if (str == str2) { Console.WriteLine("Something"); } // Is this a comparison of value? if (str.Equals(str2)) { Console.WriteLine("Something"); } // Is this a comparison of value? string.ReferenceEquals(str, str2); // Comparison of reference (True) Console.WriteLine((object)str1 == (object)str2); // Comparison of reference (True)
如果它们未在子类中重载/重载,则Equals
和==
将默认通过引用进行比较。 ReferenceEquals
将始终通过引用进行比较。
字符串是用于实验的一种令人困惑的数据类型,因为它们重载==
以实现值相等; 另外,由于它们是不可变的,因此C#通常会为同一个文字字符串重用相同的实例。 在您的代码中, str
和str2
将是同一个对象。
@Inerdia对他所说的是正确的,但我想指出为什么行string.ferenceEquals(str,str2)在你的代码示例中返回true的原因。 因为您在编译时定义了两个字符串,所以编译器可以优化代码,以便它们都可以指向字符串的同一个实例。 由于字符串是不可变的,因此即使String是引用类型,编译器也知道它可以执行此操作。 但是如果您更改代码以动态生成其中一个字符串(如下所示),则编译器无法执行此优化。 因此,在您的代码示例中,如果您将代码更改为:
string str = "hello"; string str2 = new StringBuilder().Append("he").Append("llo").ToString();
然后string.ReferenceEquals(str,str2)行现在将返回false,因为此时编译器无法重新使用相同的实例(字符串的引用)。
- string.ReferenceEquals(str,str2);
它显然比较了参考文献 - str.Equals(STR2)
试着首先比较参考文献。 然后它尝试按值进行比较。 - str == str2
与Equals相同。
比较字符串的好方法是使用string.Compare。 如果你想忽略大小写,那么也有一个参数。
ReferenceTypes和字符串的平等和比较:
引用类型的工作方式如下:
System.Object a = new System.Object(); System.Object b = new System.Object(); a == b; //returns true a.Equals(b); //returns false b = a; a == b; //returns true a.Equals(b); //returns true
由于字符串是引用类型,它们应该做同样的事情,不应该吗? 但他们没有!
C#Documentation定义字符串相等,如下所示:
尽管string是引用类型,但是定义了相等运算符(==和!=)来比较字符串对象的值,而不是引用(7.9.7字符串相等运算符)。 这使得对字符串相等性的测试更加直观。
https://msdn.microsoft.com/en-us/library/362314fe%28v=vs.71%29.aspx https://msdn.microsoft.com/en-us/library/aa664728%28v=vs.71 %29.aspx
这对您测试代码有影响。
if (str == str2) { Console.WriteLine("Something"); } // This is comparision of value even though string is a referenceType if (str.Equals(str2)) { Console.WriteLine("Something"); } // This is comparion by reference.
请记住,作为程序员(或者你的狡猾的同事)可以覆盖.Equals(),改变它的行为,你上面看到的是应该发生的事情。 它不一定符合您的代码库 – 现实,如果有疑问,请通过标记.Equals()并点击F12来查看定义。
x.Equals的附录
object.Equals()的行为应该是这些规则:
- 项目清单
- x.Equals(x)返回true。
- x.Equals(y)返回与y.Equals(x)相同的值。
- if(x.Equals(y)&& y.Equals(z))返回true,然后x.Equals(z)返回true。
- 只要未修改x和y引用的对象,x.Equals(y)的连续调用就会返回相同的值。
- x.Equals(null)返回false。 https://msdn.microsoft.com/ru-ru/library/ms173147%28v=vs.80%29.aspx
无论何时您有疑问,都可以调用x.ReferenceEquals,它的定义如下:
与Object.Equals(Object)方法和相等运算符不同,无法覆盖Object.ReferenceEquals(Object)方法。 因此,如果要测试两个对象引用是否相等,并且您不确定Equals方法的实现,则可以调用该方法。
https://msdn.microsoft.com/de-de/library/system.object.referenceequals%28v=vs.110%29.aspx
从而:
System.Object a = new System.Object(); System.Object b = a; System.Object.ReferenceEquals(a, b); //returns true
在您的示例中,编译器在优化中合并您的字符串:
string str = "hello"; string str2 = "hello"; string.ReferenceEquals(str, str2); // Comparison of reference (True)
在您的示例中,此行为仅适用于编译器优化,如果我们将代码随机化,它将返回false:
string str = "hello"; string str2 = "hello"; if(throwCoin) { str2 = "bye"; } string.ReferenceEquals(str, str2); // Comparison of reference (False)
摘自.net来源:
public bool Equals(string value) { if (this == null) throw new NullReferenceException(); else if (value == null) return false; else if (object.ReferenceEquals((object) this, (object) value)) return true; else return string.EqualsHelper(this, value); }
所以一般来说,它首先是引用的比较,如果它们不匹配,它会比较值。