C # .Equals (), .ReferenceEquals () и оператор ==

Мое понимание этих трех было:

.Equals() тесты на равенство данных (из-за отсутствия лучшего описания)..Equals() может возвращать True для разных экземпляров одного и того же объекта, и это наиболее часто переопределенный метод.

.ReferenceEquals() проверяет, являются ли два объекта одним и тем же экземпляром и не могут быть переопределены.

== такой же, какReferenceEquals() по умолчанию, но это МОЖЕТ быть отменено.

НоC # станция состояния:

В классе объектаEquals а такжеReferenceEquals методы семантически эквивалентны, за исключением того, чтоReferenceEquals работает только на экземплярах объекта.ReferenceEquals Метод статичен.

Теперь я не понимаю. Может кто-нибудь пролить некоторый свет на это?

 99999906 окт. 2010 г., 07:16
@ Привет. Меня смущает только та часть, которую я извлек из C # Station.
 Ian Mercer06 окт. 2010 г., 07:13
Увидетьstackoverflow.com/questions/814878/... и многие другие вопросы StackOverflow по этой теме.

Ответы на вопрос(7)

В классе Object .Equals реализует идентичность, а не равенство. Он проверяет, равны ли ссылки. Код может быть таким:

public virtual Boolean Equals(Object other) {
    if (this == other) return true;
    return false;
}

При реализации .Equals в вашем классе вы должны вызывать базовый класс .Equals, только если базовый класс не является Object. Да, это сложно.

Более того, производные классы могут переопределять .Equals, поэтому вы не можете вызывать его для проверки идентичности. Microsoft добавила статический метод .ReferenceEquals.

Если вы используете какой-то класс, то для васлогически .Equals проверяет равенство и .ReferenceEquals проверяет идентичность.

Ваше понимание .ReferenceEquals является правильным.

.Equals проверяет равенство данных для типов значений и ссылочное равенство для не значащих типов (общие объекты).

.Equals могут быть переопределены для объектов, чтобы выполнить некоторую форму проверки на равенство данных

РЕДАКТИРОВАТЬ: Кроме того, .ReferenceEquals не может использоваться на типах значений (ну, это может, но всегда будет ложным)

Equals() проверяет хеш-код или эквивалентность в зависимости от базового типа (значение / ссылка) иReferenceEquals() предназначен всегда проверять хеш-код.ReferenceEquals возвращаетсяtrue если оба объекта указывают на одну и ту же область памяти.

double e = 1.5;
double d = e;
object o1 = d;
object o2 = d;

Console.WriteLine(o1.Equals(o2)); // True
Console.WriteLine(Object.Equals(o1, o2)); // True
Console.WriteLine(Object.ReferenceEquals(o1, o2)); // False

Console.WriteLine(e.Equals(d)); // True
Console.WriteLine(Object.Equals(e, d)); // True
Console.WriteLine(Object.ReferenceEquals(e, d)); // False
 Jim Balter24 дек. 2017 г., 05:10
Это нонсенс. Ни Equals, ни ReferenceEquals не смотрят на HashCode. Есть просто требование, чтобы объекты HashCodes of Equals были равны. И объекты никуда не указывают ... ReferenceEquals имеет значение true, если и только если оба его аргумента являются одним и тем же ссылочным объектом или оба равны нулю.

Хочу добавить мои пять центов о сравнении с "нулем".

ReferenceEquals(объект, объект) - это то же самое, что и «(объект) arg1 == arg2» (поэтому в случае типов значений вы получаете бокс, и на это требуется время). Но этот метод - единственный 100% безопасный способ проверить ваш аргумент на ноль в нескольких ситуациях, например

а) прежде чем звонить своим членам через. операторб) проверка результата работы оператора AS.

== и равно (), Почему я говорю, что ReferenceEquals на 100% безопасен с нулевыми проверками? Представьте, что вы пишете универсальные расширения в основных межпроектных библиотеках и, допустим, вы ограничиваете тип универсального параметра некоторым типом домена. Этот тип может вводить оператор "==" - сейчас или позже (и поверьте мне, я видел много, у этого оператора может быть очень "странная" логика, особенно если это касается объектов домена или персистентности). Вы пытаетесь проверить свой аргумент для нуля, а затем вызываете операцию члена над ним. Сюрприз, вы можете иметь NullRef здесь. Потому что == оператор почти такой же, как Equals () - очень нестандартный и очень непредсказуемый. Однако есть и разница, которую следует учитывать: если вы не ограничиваете свой универсальный параметр каким-либо пользовательским типом (== можно использовать только в том случае, если ваш тип "class"), оператор == такой же, как объект .ReferenceEquals (..). Реализация equals всегда используется из окончательного типа, поскольку она виртуальная.

Поэтому я рекомендую, когда вы пишете свои собственные типы или производные от известных типов, вы можете использовать == для проверки на ноль. В противном случае используйте object.ReferenceEquals (arg, null).

Посмотри наэта статья MSDN на предмет.

Я думаю, что уместными точками являются:

Чтобы проверить равенство ссылок, используйте ReferenceEquals. Чтобы проверить равенство значений, используйте Equals или Equals.

По умолчанию оператор == проверяет равенство ссылок, определяя, указывают ли две ссылки на один и тот же объект, поэтому ссылочные типы не должны реализовывать оператор == для получения этой функциональности. Когда тип является неизменяемым, то есть данные, содержащиеся в экземпляре, не могут быть изменены, может быть полезен оператор перегрузки == для сравнения равенства значений вместо ссылочного равенства, поскольку в качестве неизменяемых объектов их можно считать одинаковыми, если они имеют такое же значение.

Надеюсь это поможет!

 Pac004 дек. 2017 г., 16:56
К сожалению, ссылка не работает. +1 за копирование соответствующей информации.
Решение Вопроса

Источник вашей путаницы заключается в том, что в выписке со станции C # есть опечатка, которая должна гласить: «... за исключением того, чтоРавно работает только на экземплярах объекта. Метод ReferenceEquals является статическим. "

Вы слабо правы в отношении различий в семантическом значении каждого из них (хотя «разные экземпляры одного и того же объекта» кажутся немного запутанными, вероятно, следует прочитать «разные экземпляры одного и того же объекта»).тип) и о котором можно отменить.

Если мы оставим это в стороне, давайте разберемся с последней частью вашего вопроса, то есть как они работают с простымSystem.Objectслучаи иSystem.Objectссылки (нам нужно, чтобы уклониться от неполиморфной природы==). Здесь все три операции будут работатьequivalentallyно с оговоркой:Equalsне может быть вызван наnull.

Equalsэто метод экземпляра, который принимаетодин параметр (которыйМожно бытьnull). Так как это метод экземпляра (должен вызываться на реальном объекте), он не может быть вызван наnull-ссылка.

ReferenceEquals это статический метод, который принимаетдва параметры, либо / оба из которых могут бытьnull, Так как он статический (не связан с объектомпример), это не броситNullReferenceException при любых обстоятельствах.

==является оператором, который в этом случае (object), ведет себя идентичноReferenceEquals, Это не броситNullReferenceExceptionили.

Проиллюстрировать:

object o1 = null;
object o2 = new object();

//Technically, these should read object.ReferenceEquals for clarity, but this is redundant.
ReferenceEquals(o1, o1); //true
ReferenceEquals(o1, o2); //false
ReferenceEquals(o2, o1); //false
ReferenceEquals(o2, o2); //true

o1.Equals(o1) //NullReferenceException
o1.Equals(o2) //NullReferenceException
o2.Equals(o1) //false
o2.Equals(o2) //true
 weston30 нояб. 2012 г., 16:20
Equals также статический методobject который принимает два параметра. Один или оба могут бытьnull.
 Domenic06 окт. 2010 г., 07:34
Выдержка заявляет"вobject учебный класс", Я думаю, что вы пропустили эту часть? Потому что в противном случае вы бы не говорили о переопределении.
 Ani06 окт. 2010 г., 09:20
@saj: Чтобы уточнить, предложение не означает, что статические методы в целом не могут генерировать исключения NullReferenceExceptions. «Обстоятельства», на которые я здесь ссылаюсь, состоят в том,null, Извинения, я думал, что это подразумевается.
 Ani06 окт. 2010 г., 07:22
Да. Обновил мой ответ.
 Ani06 окт. 2010 г., 07:37
Мой ответтолько оobject учебный класс.
 selvaraj06 окт. 2010 г., 09:15
@Ani: в приведенном ниже предложении неверный статический метод может вызвать исключение NullReferenceException: поскольку оно является статическим (не связано с экземпляром объекта), оно не будет генерировать исключение NullReferenceException ни при каких обстоятельствах.
 99999906 окт. 2010 г., 07:17
Так что цитата из станции C #, приведенной выше, неверна (особенно если я переопределил.Equals())?

Я расширил наОтличный ответ Ани показать ключевые различия при работе со ссылочными типами и переопределенными методами равенства.

Вы можете увидеть рабочую версию этого кода здесь:https://dotnetfiddle.net/dFKMhBКроме того, этот код может быть вставлен вLINQPad и беги какLanguage: C# Program.

.

void Main()
{

    //odd os are null; evens are not null
    object o1 = null;
    object o2 = new object();
    object o3 = null;
    object o4 = new object();
    object o5 = o1;
    object o6 = o2;

    Demo d1 = new Demo(Guid.Empty);
    Demo d2 = new Demo(Guid.NewGuid());
    Demo d3 = new Demo(Guid.Empty);

    Debug.WriteLine("comparing null with null always yields true...");
    ShowResult("ReferenceEquals(o1, o1)", () => ReferenceEquals(o1, o1)); //true
    ShowResult("ReferenceEquals(o3, o1)", () => ReferenceEquals(o3, o1)); //true
    ShowResult("ReferenceEquals(o5, o1)", () => ReferenceEquals(o5, o1)); //true 
    ShowResult("o1 == o1", () => o1 == o1); //true
    ShowResult("o3 == o1", () => o3 == o1); //true
    ShowResult("o5 == o1", () => o5 == o1); //true 

    Debug.WriteLine("...though because the object's null, we can't call methods on the object (i.e. we'd get a null reference exception).");
    ShowResult("o1.Equals(o1)", () => o1.Equals(o1)); //NullReferenceException
    ShowResult("o1.Equals(o2)", () => o1.Equals(o2)); //NullReferenceException
    ShowResult("o3.Equals(o1)", () => o3.Equals(o1)); //NullReferenceException
    ShowResult("o3.Equals(o2)", () => o3.Equals(o2)); //NullReferenceException
    ShowResult("o5.Equals(o1)", () => o5.Equals(o1));  //NullReferenceException
    ShowResult("o5.Equals(o2)", () => o5.Equals(o1));  //NullReferenceException

    Deb,ug.WriteLine("Comparing a null object with a non null object always yeilds false");
    ShowResult("ReferenceEquals(o1, o2)", () => ReferenceEquals(o1, o2)); //false
    ShowResult("ReferenceEquals(o2, o1)", () => ReferenceEquals(o2, o1)); //false
    ShowResult("ReferenceEquals(o3, o2)", () => ReferenceEquals(o3, o2)); //false
    ShowResult("ReferenceEquals(o4, o1)", () => ReferenceEquals(o4, o1)); //false
    ShowResult("ReferenceEquals(o5, o2)", () => ReferenceEquals(o3, o2)); //false
    ShowResult("ReferenceEquals(o6, o1)", () => ReferenceEquals(o4, o1)); //false
    ShowResult("o1 == o2)", () => o1 == o2); //false
    ShowResult("o2 == o1)", () => o2 == o1); //false
    ShowResult("o3 == o2)", () => o3 == o2); //false
    ShowResult("o4 == o1)", () => o4 == o1); //false
    ShowResult("o5 == o2)", () => o3 == o2); //false
    ShowResult("o6 == o1)", () => o4 == o1); //false
    ShowResult("o2.Equals(o1)", () => o2.Equals(o1)); //false
    ShowResult("o4.Equals(o1)", () => o4.Equals(o1)); //false
    ShowResult("o6.Equals(o1)", () => o4.Equals(o1)); //false

    Debug.WriteLine("(though again, we can't call methods on a null object:");
    ShowResult("o1.Equals(o2)", () => o1.Equals(o2)); //NullReferenceException
    ShowResult("o1.Equals(o4)", () => o1.Equals(o4)); //NullReferenceException
    ShowResult("o1.Equals(o6)", () => o1.Equals(o6)); //NullReferenceException

    Debug.WriteLine("Comparing 2 references to the same object always yields true");
    ShowResult("ReferenceEquals(o2, o2)", () => ReferenceEquals(o2, o2)); //true    
    ShowResult("ReferenceEquals(o6, o2)", () => ReferenceEquals(o6, o2)); //true <-- Interesting
    ShowResult("o2 == o2", () => o2 == o2); //true  
    ShowResult("o6 == o2", () => o6 == o2); //true <-- Interesting
    ShowResult("o2.Equals(o2)", () => o2.Equals(o2)); //true 
    ShowResult("o6.Equals(o2)", () => o6.Equals(o2)); //true <-- Interesting

    Debug.WriteLine("However, comparing 2 objects may yield false even if those objects have the same values, if those objects reside in different address spaces (i.e. they're references to different objects, even if the values are similar)");
    Debug.WriteLine("NB: This is an important difference between Reference Types and Value Types.");
    ShowResult("ReferenceEquals(o4, o2)", () => ReferenceEquals(o4, o2)); //false <-- Interesting
    ShowResult("o4 == o2", () => o4 == o2); //false <-- Interesting
    ShowResult("o4.Equals(o2)", () => o4.Equals(o2)); //false <-- Interesting

    Debug.WriteLine("We can override the object's equality operator though, in which case we define what's considered equal");
    Debug.WriteLine("e.g. these objects have different ids, so we treat as not equal");
    ShowResult("ReferenceEquals(d1,d2)",()=>ReferenceEquals(d1,d2)); //false
    ShowResult("ReferenceEquals(d2,d1)",()=>ReferenceEquals(d2,d1)); //false
    ShowResult("d1 == d2",()=>d1 == d2); //false
    ShowResult("d2 == d1",()=>d2 == d1); //false
    ShowResult("d1.Equals(d2)",()=>d1.Equals(d2)); //false
    ShowResult("d2.Equals(d1)",()=>d2.Equals(d1)); //false
    Debug.WriteLine("...whilst these are different objects with the same id; so we treat as equal when using the overridden Equals method...");
    ShowResult("d1.Equals(d3)",()=>d1.Equals(d3)); //true <-- Interesting (sort of; different to what we saw in comparing o2 with o6; but is just running the code we wrote as we'd expect)
    ShowResult("d3.Equals(d1)",()=>d3.Equals(d1)); //true <-- Interesting (sort of; different to what we saw in comparing o2 with o6; but is just running the code we wrote as we'd expect)
    Debug.WriteLine("...but as different when using the other equality tests.");
    ShowResult("ReferenceEquals(d1,d3)",()=>ReferenceEquals(d1,d3)); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
    ShowResult("ReferenceEquals(d3,d1)",()=>ReferenceEquals(d3,d1)); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
    ShowResult("d1 == d3",()=>d1 == d3); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
    ShowResult("d3 == d1",()=>d3 == d1); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)


    Debug.WriteLine("For completeness, here's an example of overriding the == operator (wihtout overriding the Equals method; though in reality if overriding == you'd probably want to override Equals too).");
    Demo2 d2a = new Demo2(Guid.Empty);
    Demo2 d2b = new Demo2(Guid.NewGuid());
    Demo2 d2c = new Demo2(Guid.Empty);
    ShowResult("d2a == d2a", () => d2a == d2a); //true
    ShowResult("d2b == d2a", () => d2b == d2a); //false
    ShowResult("d2c == d2a", () => d2c == d2a); //true <-- interesting
    ShowResult("d2a != d2a", () => d2a != d2a); //false
    ShowResult("d2b != d2a", () => d2b != d2a); //true
    ShowResult("d2c != d2a", () => d2c != d2a); //false <-- interesting
    ShowResult("ReferenceEquals(d2a,d2a)", () => ReferenceEquals(d2a, d2a)); //true
    ShowResult("ReferenceEquals(d2b,d2a)", () => ReferenceEquals(d2b, d2a)); //false
    ShowResult("ReferenceEquals(d2c,d2a)", () => ReferenceEquals(d2c, d2a)); //false <-- interesting
    ShowResult("d2a.Equals(d2a)", () => d2a.Equals(d2a)); //true
    ShowResult("d2b.Equals(d2a)", () => d2b.Equals(d2a)); //false
    ShowResult("d2c.Equals(d2a)", () => d2c.Equals(d2a)); //false <-- interesting   

}



//this code's just used to help show the output in a friendly manner
public delegate bool Statement();
void ShowResult(string statementText, Statement statement)
{
    try 
    {
        Debug.WriteLine("\t{0} => {1}",statementText, statement());
    }
    catch(Exception e)
    {
        Debug.WriteLine("\t{0} => throws {1}",statementText, e.GetType());
    }
}

class Demo
{
    Guid id;
    public Demo(Guid id) { this.id = id; }
    public override bool Equals(object obj)
    {
        return Equals(obj as Demo); //if objects are of non-comparable types, obj will be converted to null
    }
    public bool Equals(Demo obj)
    {
        if (obj == null)
        {
            return false;
        }
        else
        {
            return id.Equals(obj.id);
        }
    }
    //if two objects are Equal their hashcodes must be equal
    //however, if two objects hash codes are equal it is not necessarily true that the objects are equal
    //i.e. equal objects are a subset of equal hashcodes
    //more info here: https://stackoverflow.com/a/371348/361842
    public override int GetHashCode()
    {
        return id.GetHashCode();
    }
}

class Demo2
{
    Guid id;
    public Demo2(Guid id)
    {
        this.id = id;
    }

    public static bool operator ==(Demo2 obj1, Demo2 obj2)
    {
        if (ReferenceEquals(null, obj1)) 
        {
            return ReferenceEquals(null, obj2); //true if both are null; false if only obj1 is null
        }
        else
        {
            if(ReferenceEquals(null, obj2)) 
            {
                return false; //obj1 is not null, obj2 is; therefore false
            }
            else
            {
                return obj1.id == obj2.id; //return true if IDs are the same; else return false
            }
        }
    }

    // NB: We also HAVE to override this as below if overriding the == operator; this is enforced by the compiler.  However, oddly we could choose to override it different to the below; but typically that would be a bad idea...
    public static bool operator !=(Demo2 obj1, Demo2 obj2)
    {
        return !(obj1 == obj2);
    }
}

Ваш ответ на вопрос