[英]Comparing VALUE and REFERENCE of types
我知道有很多方法可以在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.ReferenceEquals(str,str2)返回true的原因。 由于您是在编译时定义两个字符串的,因此编译器可以优化代码,以便它们都可以指向字符串的同一实例。 由于字符串是不可变的,因此即使String是引用类型,编译器也知道可以做到这一点。 但是,如果您更改代码以动态生成字符串之一(如下所示),则编译器将无法执行此优化。 因此,在您的代码示例中,如果将代码更改为:
string str = "hello";
string str2 = new StringBuilder().Append("he").Append("llo").ToString();
然后string.ReferenceEquals(str,str2)行现在将返回false,因为这一次编译器无法知道重用同一实例(字符串的引用)。
引用类型的工作方式如下:
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#文档定义字符串相等性,如下所示:
尽管string是引用类型,但定义了相等运算符(==和!=)来比较字符串对象的值,而不是引用(7.9.7字符串相等运算符)。 这使得测试字符串相等性更加直观。
https://msdn.microsoft.com/zh-CN/library/362314fe%28v=vs.71%29.aspx https://msdn.microsoft.com/zh-CN/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 comparison by value too, because Equals is overrided in String class.
请记住,作为程序员(或者您棘手的同事),您可以覆盖.Equals(),更改其行为,上面您所看到的就是应该发生的事情。 如果有疑问,可以通过标记.Equals()并按F12来检查定义,这不一定符合您的代码库现实。
object.Equals()的行为应遵循以下规则:
- 项目清单
- x.Equals(x)返回true。
- x.Equals(y)返回与y.Equals(x)相同的值。
- 如果(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)
比较字符串的一个好方法是使用string.Compare。 如果要忽略大小写,也可以使用一个参数。
.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);
}
因此,通常是先比较参考,如果不匹配,则比较值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.