Overload == (и! =, конечно), могу ли я обходить ==, чтобы определить, является ли объект нулевым
когда я пытаюсь перегрузить operator == и!= в С# и переопределить Equal в соответствии с рекомендациями, я обнаружил, что у меня нет возможности отличить обычный объект и null. Например, я определил класс Complex.
public static bool operator ==(Complex lhs, Complex rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !lhs.Equals(rhs);
}
public override bool Equals(object obj)
{
if (obj is Complex)
{
return (((Complex)obj).Real == this.Real &&
((Complex)obj).Imaginary == this.Imaginary);
}
else
{
return false;
}
}
Но когда я хочу использовать
if (temp == null)
Когда temp действительно null, происходит какое-то исключение. И я не могу использовать ==, чтобы определить, является ли lhs нулевым, что вызовет бесконечный цикл.
Что мне делать в этой ситуации.
Один из способов, о котором я могу думать, - это что-то вроде Class.Equal(object, object) (если оно существует) для обхода ==, когда я делаю проверку.
Каков нормальный способ решения проблемы?
Спасибо.
Ответы
Ответ 1
Вы должны использовать статический метод Equals в перегрузках оператора (который вызовет метод Equals экземпляра):
public static bool operator ==(Complex lhs, Complex rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !Equals(lhs, rhs);
}
Примечание. Вы также можете проверить null
в методе Equals.
Вы также можете прочитать Object.Equals Topic на MSDN, который является отличным источником образцов.
Ответ 2
В верхней части вашего переопределения Equals вы можете использовать следующее:
if (Object.ReferenceEquals(obj, null))
return false;
Исключением, которое вы получаете, вероятно, является исключение StackOverflowException, потому что ваш оператор == вызывает бесконечную рекурсию.
EDIT:
Если Complex - это структура, у вас не должно быть никаких проблем с NullReferenceExceptions. Если Complex является классом, вы можете изменить свою реализацию перегрузок == и! =, Чтобы избежать исключения (Laurent Etiemble уже указал это в своем ответе):
public static bool operator ==(Complex lhs, Complex rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !Equals(lhs, rhs);
}
Ответ 3
public static bool operator ==(Complex lhs, Complex rhs)
{
if (Object.ReferenceEquals(lhs, null))
{
return Object.ReferenceEquals(rhs, null);
}
return lhs.Equals(rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !(lhs == rhs);
}
Бедный человек unit test
Action<Complex, Complex> tester = (left, right) =>
{
Console.WriteLine(left == right);
Console.WriteLine(left != right);
Console.WriteLine(left == null);
Console.WriteLine(left != null);
Console.WriteLine("---");
};
tester(new Complex(), new Complex());
tester(null, new Complex());
tester(null, null);
tester(new Complex(), null);
Ответ 4
Существует более удобный подход с использованием операторов is
и cast
:
Complex c = obj as Complex;
return (c != null) && (c.Real == this.Real) && (c.Imaginary == this.Imaginary);
Ниже приведен быстрый тест относительно оператора Equals
и сравнение с null
:
class Complex
{
public override bool Equals(object obj)
{
if (obj is Complex)
{
return true;
}
else
{
return false;
}
}
}
Отладка не входит в тело оператора:
var b = (new Complex() == new Complex());
Ответ 5
Я думаю, что вы shoud проверяете значение null в реализации оператора ==. В противном случае, когда lhs равно null, вы вызываете Complex (null).Equals(я не знаю, для С#, но в Java это будет исключение Nullpointer)
Чтобы проверить значение null, я предлагаю что-то вроде:
if (null == lhs && null == rhs) return true
else if (null == lhs) return false
else return lhs.Equals(rhs);
Итак, Object.Equals будут вызываться для всех == сравнений выше.