На этот вопрос нет простого ответа. Любой, кто говорит, всегда использует тот или иной, дает вам плохие советы, на мой взгляд.
Существует несколько различных методов, которые вы можете вызвать для сравнения экземпляров объектов. С учетом двух объектов экземпляров a
и b
, вы могли бы написать:
Object.Equals(a,b)
Object.ReferenceEquals(a,b)
a.Equals(b)
a == b
Они все могли бы делать разные вещи!
Object.Equals(a,b)
будет (по умолчанию) выполняет эталонное сравнение равенства ссылочных типов и побитовое сравнение по типам значений.Из документации MSDN:
Реализация по умолчанию Равных поддерживает равенство ссылок для ссылочных типов, и побитового равенство для типов значений. Ссылка равенство означает ссылки на объекты, которые сравниваемых относятся к одному объекту. Поразрядное равенство означает, что объекты, которые сравниваются, имеют одинаковое двоичное представление .
Обратите внимание, что производный тип может переопределить метод Equals до реализовать равенство значения. Значение равенство означает, что сравниваемые объекты имеют одинаковое значение, но разные двоичные представления.
Обратите внимание на предыдущий параграф выше ... мы поговорим об этом чуть позже.
Object.ReferenceEquals(a,b)
выполняет только сравнение сравнения ссылок. Если пройденные типы являются типами в штучной упаковке, результат всегда равен false
.
a.Equals(b)
вызывает виртуальный метод экземпляра Object
, что тип a
может переопределить делать все, что хочет. Вызов выполняется с использованием виртуальной диспетчеризации, поэтому выполняемый код зависит от типа времени выполнения a
.
a == b
вызывает статический перегруженный оператор ** время компиляции типа * из a
. Если реализация этого оператора вызывает методы экземпляра на a
или b
, это также может зависеть от типов параметров выполнения. Так как отправка на основе типов в выражении, нижеследующий может давать разные результаты:
Frog aFrog = new Frog();
Frog bFrog = new Frog();
Animal aAnimal = aFrog;
Animal bAnimal = bFrog;
// not necessarily equal...
bool areEqualFrogs = aFrog == bFrog;
bool areEqualAnimals = aAnimal = bAnimal;
Так что, да, есть уязвимость для проверки на нули с помощью operator ==
. На практике большинство типов не перегрузка ==
- но никогда не существует гарантии.
Метод экземпляра Equals()
здесь не лучше. В то время как реализация по умолчанию выполняет проверку ссылок/побитовое равенство, тип может переопределить метод члена , и в этом случае эта реализация будет вызвана. Реализация, предоставленная пользователем, может вернуть все, что захочет, даже при сравнении с нулевым.
Но как насчет статической версии Object.Equals()
? Может ли это привести код пользователя? Ну, получается, что ответ ДА. Реализация Object.Equals(a,b)
расширяется к чему-то вдоль линий:
((object)a == (object)b) || (a != null && b != null && a.Equals(b))
Вы можете попробовать это для себя:
class Foo {
public override bool Equals(object obj) { return true; } }
var a = new Foo();
var b = new Foo();
Console.WriteLine(Object.Equals(a,b)); // outputs "True!"
Как следствие, это возможно за заявление: Object.Equals(a,b)
для запуска кода пользователя, когда ни типов в вызове null
.Обратите внимание, что Object.Equals(a,b)
не вызывает экземпляр версии Equals()
, если любой из аргументов равен NULL.
Вкратце, поведение сравнения, которое вы получаете, может значительно различаться в зависимости от того, какой метод вы выберете. Один комментарий здесь, однако: Microsoft официально не документирует внутреннее поведение Object.Equals(a,b)
. Если вам нужен утюг одетой gaurantee сравнения ссылку на нуль без какой-либо другой код работает, вы хотите Object.ReferenceEquals()
:
Object.ReferenceEquals(item, null);
Этот метод делает намерение extremently ясно - вы определенно ожидают, что результат будет сравнение двух ссылок для ссылочного равенства. Преимущество здесь более, используя нечто вроде Object.Equals(a,null)
, является то, что это менее вероятно, что кто-то придет позже и сказать:
«Эй, это неудобно, давайте заменим его: a.Equals(null)
или a == null
, которые потенциально могут быть различными.
Давайте придать некоторый прагматизм здесь, однако. до сих пор мы говорили о потенциале различных методов сравнения, дава различные результаты. Хотя это, конечно, дело, есть определенные типы, где это безопасный ite a == null
. Встроенные классы .NET, такие как String
и Nullable<T>
, имеют четкую семантику для сравнения. Кроме того, они sealed
- предотвращение любых изменений их поведения через наследование. Ниже довольно часто (и правильно):
string s = ...
if(s == null) { ... }
Это ненужно (и некрасиво) написать:
if(ReferenceEquals(s,null)) { ... }
Так в некоторых ограниченных случаях использование ==
является безопасным и целесообразным.
Я думал, что мой ответ (ответ Microsoft по доверенности) - довольно простой ответ. – mquander
Вопросы типа: * «Должен ли я всегда/никогда не делать X» * подразумевать разрыв в знаниях о нюансах рассматриваемого предмета. Я чувствовал, что немного более подробно было бы полезно здесь, чтобы прояснить, почему я не думаю, что простой ответ имеет смысл. – LBushkin
Статический метод 'object.Equals (a, b)' может фактически вызвать перегруженный/виртуальный метод «Equals» на объекте 'a'. Если я правильно помню, он делает что-то вроде '((object) a == (объект) b) || (a! = null && b! = null && a.Equals (b)) '. (Это не имеет значения, если сравнивать с «null», о чем спрашивает OP, но имеет отношение к общему случаю.) – LukeH