1

我知道有很多方法可以在 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)
4

5 回答 5

4

Equals==如果它们没有在子类中被覆盖/重载,则默认情况下将通过引用进行比较。ReferenceEquals将始终通过引用进行比较。

字符串是一种令人困惑的数据类型,用于试验这一点,因为它们重载==以实现值相等;此外,由于它们是不可变的,C# 通常会为相同的文字字符串重用相同的实例。在您的代码中,strstr2将是同一个对象。

于 2011-10-19T12:43:26.610 回答
2

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

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

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

于 2011-10-19T12:59:16.020 回答
1
  1. string.ReferenceEquals(str, str2);
    它显然比较了参考文献。
  2. str.Equals(str2)
    首先尝试比较引用。然后它尝试按值进行比较。
  3. str == str2
    与 Equals 相同。

比较字符串的一个好方法是使用 string.Compare。如果你想忽略大小写,也有一个参数。

于 2011-10-19T12:58:28.227 回答
1

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# 文档定义字符串相等,如下所示:

尽管字符串是一种引用类型,但相等运算符(== 和 !=)被定义为比较字符串对象的值,而不是引用(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 comparison by value too, because Equals is overrided in String class.

请记住,您作为程序员(或您棘手的同事)可以覆盖 .Equals(),改变它的行为,您在上面看到的是应该发生的事情。它不一定符合您的代码库现实,如有疑问,请通过标记 .Equals() 并按 F12 查看定义。

x.Equals 的附录

object.Equals() 的行为应该遵循以下规则:

  • 项目清单
  • x.Equals(x) 返回真。
  • 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)
于 2017-04-12T15:29:33.957 回答
0

摘自.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);
}

所以一般来说,它首先是引用比较,如果它们不匹配,它会比较值。

于 2011-10-19T12:43:33.367 回答