Зачем мне когда-либо хотеть сделать object.ReferenceEquals(null, this) в переопределении Equals?
Рассмотрим следующий код, который я просматривал:
public override bool Equals(object other)
{
return !object.ReferenceEquals(null, this)
&& (object.ReferenceEquals(this, other)
|| ((other is MyType) && this.InternalEquals((MyType)other)));
}
Первая строка в этом коде вызвала мое любопытство. Всякий раз, когда this
равен нулю, метод должен возвращать false. Теперь я уверен, что программист хотел написать !object.ReferenceEquals(other, null)
, чтобы сочетать ситуации с null
, но он настаивает на том, что this
может быть нулевым Я настаиваю на том, что это невозможно (если кто-то не использует прямую манипуляцию с памятью). Должны ли мы оставить это в?
2 ответа
Хотя я, конечно, не проверю this
для нуля, это возможно, без какой-либо реальной злобности памяти - просто немного размышлений:
using System;
public class Test
{
public void CheckThisForNullity()
{
Console.WriteLine("Is this null? {0}", this == null);
}
static void Main(string[] args)
{
var method = typeof(Test).GetMethod("CheckThisForNullity");
var openDelegate = (Action<Test>) Delegate.CreateDelegate(
typeof(Action<Test>), method);
openDelegate(null);
}
}
Кроме того, генерировать IL, который использует call
вместо callvirt
вызвать метод экземпляра для нулевой цели. Вполне законно, просто не то, что обычно делает компилятор C#.
Это не имеет ничего общего с завершением, которое само по себе волосатое, но по-разному. Финализатор может запускаться во время выполнения метода экземпляра, если CLR может доказать, что вы не собираетесь использовать какие-либо поля в экземпляре (что я бы настоятельно ожидал включить this
ссылка).
Что касается представленного кода - нет, похоже, это просто ошибка. Я бы переписал это как:
public override bool Equals(object other)
{
return Equals(other as MyType);
}
public bool Equals(MyType other)
{
if (ReferenceEquals(other, null))
{
return false;
}
// Now perform the equality check
}
... при условии, что MyType
это класс, а не структура. Обратите внимание, как я использую другой публичный метод с правильным типом параметра - я бы реализовал IEquatable<MyType>
в то же время.
C# обычно не позволяет вызывать методы null
, Я думаю, что программист, который написал это, происходит из C++ (где, я думаю, можно вызывать методы null
до тех пор, пока они не имеют доступа к элементу данных this
) или писать с защитой для особых сценариев (таких как вызов отражением, как уже было сказано).