Сравнение VALUE и ССЫЛКИ типов - PullRequest
1 голос
/ 19 октября 2011

Я знаю, что есть много способов сравнить VALUE и REFERENCES в C #, но я все еще немного озадачен тем, какой тип выполняет то, что и когда вы пытаетесь сравнить 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)

Ответы [ 5 ]

4 голосов
/ 19 октября 2011

Equals и == будут сравниваться по ссылке по умолчанию, если они не переопределены / перегружены в подклассе. ReferenceEquals всегда будет сравниваться по ссылке.

Строки - это вводящий в заблуждение тип данных, используемый для экспериментов с этим, потому что они перегружают == для реализации равенства значений; Кроме того, поскольку они неизменяемы, C # обычно повторно использует один и тот же экземпляр для одной и той же строки. В вашем коде str и str2 будут одним и тем же объектом.

2 голосов
/ 19 октября 2011

@ Инердиа прав в том, что он говорит, но я хотел бы указать причину, по которой строка string.ReferenceEquals (str, str2) возвращает true в вашем примере кода.Поскольку вы определяете обе строки во время компиляции, компилятор может оптимизировать код, чтобы они оба могли указывать на один и тот же экземпляр строки.Поскольку строки неизменяемы, компилятор знает, что может это сделать, даже если String является ссылочным типом.Но если вы измените свой код для динамической генерации одной из строк (как показано ниже), компилятор не сможет выполнить эту оптимизацию.Таким образом, в вашем примере кода, если вы измените свой код на:

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

Тогда строка string.ReferenceEquals (str, str2) теперь вернет false, поскольку на этот раз компилятор не может знать, чтобы повторно использовать тот же экземпляр(ссылка на строку).

1 голос
/ 12 апреля 2017

Равенство и сравнение эталонных типов и строк:

Типы ссылок работают следующим образом:

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

Поведение объекта. Эквалайзеры () должны эти правила:

  • Элемент списка
  • x.Equals (x) возвращает true.
  • x.Equals (y) возвращает то же значение, что и y.Equals (x).
  • если (x.Equals (y) && y.Equals (z)) возвращает true, тогда x.Equals (z) возвращает true.
  • Последовательные вызовы x.Equals (y) возвращают одно и то же значение до тех пор, пока объекты, на которые ссылаются x и 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 голос
/ 19 октября 2011
  1. string.ReferenceEquals (str, str2);
    Это явно сравнивает ссылки.
  2. str.Equals (str2)
    Пытается сначала сравнить ссылки. Затем он пытается сравнить по значению.
  3. str == str2
    Делает то же самое, что и Equals.

Хороший способ сравнения строк - использовать string.Compare. Если вы хотите игнорировать регистр, для этого также есть параметр.

0 голосов
/ 19 октября 2011

Выдержка из источников .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);
}

Итак, в общем, сначала выполняется сравнение ссылок, а если они не совпадают, сравниваются значения.

...