Почему делают это:
// If parameter cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if ((System.Object)p == null)
{
return false;
}
Вместо этого:
// If parameter cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if (p == null)
{
return false;
}
Я не понимаю, почему Вы когда-либо писали бы ((Система. Объект) p)?
С уважением,
Dan
Вы приводите к object
, когда не знаете или не можете быть уверены, что исходный класс переопределил operator ==
:
using System;
class AlwaysEqual
{
public static bool operator ==(AlwaysEqual a, AlwaysEqual b)
{
return true;
}
public static bool operator !=(AlwaysEqual a, AlwaysEqual b)
{
return true;
}
}
class Program
{
static void Main()
{
object o = new AlwaysEqual();
AlwaysEqual ae = o as AlwaysEqual;
if (ae == null)
{
Console.WriteLine("ae is null");
}
if ((object)ae == null)
{
Console.WriteLine("(object)ae is null");
}
}
}
Этот код выводит only "ae is null"
, что явно не соответствует действительности. Приведение к object
позволяет избежать AlwaysEqual
класса operator ==
и поэтому является истинной проверкой ссылки на null
.
Каждый объект в .NET является производным от System.Object, поэтому нет необходимости в явном приведении.
Говоря простым языком, это бессмысленно. Null всегда может быть присвоен (за исключением non-nullables, таких как ints и structs) независимо от типа, поэтому его всегда можно проверить. Приведение не обязательно
Если TwoDPoint
является не нулевым типом, таким как struct, то у него действительно может быть точка. Кэш (System.Object)
фактически превратит struct в объект с нулевым значением. Но если бы это было так, то obj as TwoDPoint
был бы недействителен. Вам понадобится obj as TwoDPoint?
, чтобы сделать его nullable. (нельзя использовать as с ненулевыми объектами)
И еще более кратким будет:
if (!(obj is TwoDPoint)) {
return false;
}
Это имеет смысл, если этот код находится внутри переопределения Object.Equals
и вы не хотите вызывать оператор равенства (который может, например, ошибочно вызвать Equals
) . Приведение к объекту позволяет вызвать стандартный оператор равенства, который сравнивает ссылки.
Обычно используется Object.ReferenceEquals
для сравнения экземпляра объекта с null
внутри переопределения Equals
.
Например, это может вызвать переполнение стека:
public class Point {
public override bool Equals (object other) {
var otherPoint = other as Point;
if (other == null)
return false;
//...
}
public static bool operator == (Point l, Point r) {
//...
//null checks
if (!l.Equals(r))
return false;
}
}
В приведенном выше примере оператор равенства вызывает Equals
и потому, что переменная otherPoint
имеет тип Point
, он вызовет оператор равенства, вызывая бесконечную рекурсию.
Обычно, когда вы переопределяете Equals
и определяете оператор равенства, вы помещаете логику сравнения в оператор и вызываете ее из переопределения Equals
. Имейте в виду, что рекомендуется, чтобы класс был неизменным, если оба они переопределены.
public class Point {
public override bool Equals (object other) {
var otherPoint = other as Point;
return this == otherPoint;
}
//must override GetHashCode() as well
public static bool operator == (Point l, Point r) {
if (Object.ReferenceEquals(l, null) && Object.ReferenceEquals(r, null))
return true;
if (Object.ReferenceEquals(l, null) || Object.ReferenceEquals(r, null))
return false;
//actual equality checks
}
public static bool operator != (Point l, Point r) {
return !(l==r);
}
}