繁体   English   中英

比较类型的VALUE和REFERENCE

[英]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#通常会将相同的实例重用于相同的文字字符串。 在您的代码中, strstr2将是同一对象。

@Inerdia对他说的是正确的,但我想指出在您的代码示例中行string.ReferenceEquals(str,str2)返回true的原因。 由于您是在编译时定义两个字符串的,因此编译器可以优化代码,以便它们都可以指向字符串的同一实例。 由于字符串是不可变的,因此即使String是引用类型,编译器也知道可以做到这一点。 但是,如果您更改代码以动态生成字符串之一(如下所示),则编译器将无法执行此优化。 因此,在您的代码示例中,如果将代码更改为:

string str = "hello";
string str2 = new StringBuilder().Append("he").Append("llo").ToString(); 

然后string.ReferenceEquals(str,str2)行现在将返回false,因为这一次编译器无法知道重用同一实例(字符串的引用)。

ReferenceType和字符串的相等性和比较:

引用类型的工作方式如下:

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来检查定义,这不一定符合您的代码库现实。

x。等于的附录

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)
  1. string.ReferenceEquals(str,str2);
    它显然是比较参考。
  2. str。等于(str2)
    首先尝试比较参考。 然后,它尝试按值进行比较。
  3. str == str2
    等于等于。

比较字符串的一个好方法是使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM