我没有使用 C# 的经验,但据我所知,这在成员函数中不能为空(至少在 C++ 和 Java 中是这样,我知道的语言)
让我们首先指出您的陈述是错误的。
在 C++ 中,在 null 接收器上调度方法是未定义的行为,未定义的行为意味着任何事情都可能发生。“任何事情”包括程序传递和继续,就好像没有任何问题一样NULL
。this
当然,在 C++ 中检查是否为 null 有点愚蠢,因为只有在您已经不知道程序在做什么的情况this
下,检查才能为真,因为它的行为是未定义的。
在Java中是否this
可以为空我不知道。
现在解决您关于 C# 的问题。让我们假设它==
没有超载。我们稍后会回到这一点。
您的方法是用 C# 编写的。假设它是从具有空接收器的 C# 程序调用的。C# 编译器评估接收器是否可能为空;如果它可能为空,那么它确保它在调用该方法之前生成执行空检查的代码。因此,在这种情况下,此检查毫无意义。这当然是 99.9999% 的可能性。
假设它是通过反射调用的,就像在 mike z 的回答中一样。在这种情况下,执行调用的不是 C# 语言;相反,有人故意滥用反射。
假设它是从另一种语言调用的。我们有一个虚方法;如果它是通过虚拟调度从其他语言调用的,则必须执行空检查,因为我们怎么知道虚拟槽中的内容?在那种情况下,它不能为空。
但是假设它是使用非虚拟调度从另一种语言调用的。在这种情况下,其他语言不需要实现检查 null 的 C# 功能。它可以调用它并传递 null。
所以有几种方法this
可以null
在 C# 中使用,但它们都非常脱离主流。因此,很少有人像您的教授那样编写代码。C# 程序员习惯性地认为this
不是null
并且永远不会检查它。
现在我们已经解决了这个问题,让我们再批评一下这段代码。
public override bool Equals(object o) {
if (o == null)
return (this == null);
else {
return ((o is Person) && (this.dni == (o as Person).dni));
}
}
首先有一个明显的错误。我们假设它this
可能是空的,好的,让我们运行它。 什么停止this.dni
抛出空引用异常???如果您要假设它this
可以为空,那么至少要始终如一地这样做!(在 Coverity,我们将这种情况称为“前向空缺陷”。)
接下来:我们覆盖Equals
然后使用==
inside,大概是指引用相等。这条路是疯狂的!现在我们有一种情况,x.Equals(y)
可以是真的,x==y
也可以是假的!这太可怕了。请不要去那里。如果您要覆盖,Equals
则同时重载==
,并IEquatable<T>
在您使用时实施。
(现在,有一个合理的论点是疯狂存在于任何一个方向;如果与值语义==
一致,则可以不同于,这似乎也很奇怪。这里的要点是 C# 中的相等性相当混乱。)Equals
personx == persony
(object)personx == (object)persony
此外:如果==
稍后被覆盖怎么办?当代码的作者明确希望进行参考比较时,现在Equals
正在调用重写的运算符。==
这是错误的秘诀。
我的建议是 (1) 编写一个做正确事情的静态方法,以及 (2)ReferenceEquals
每次都使用可能对相等的含义有任何混淆的情况:
private static bool Equals(Person x, Person y)
{
if (ReferenceEquals(x, y))
return true;
else if (ReferenceEquals(x, null))
return false;
else if (ReferenceEquals(y, null))
return false;
else
return x.dni == y.dni;
}
这很好地涵盖了所有情况。请注意,当引用相等语义的含义时,读者非常清楚。另请注意,此代码可以很容易地在每种可能性上放置断点,以进行调试。最后,请注意我们尽早采取最便宜的方式;如果对象的引用相等,那么我们就不必对字段进行潜在的昂贵比较!
现在其他方法很简单:
public static bool operator ==(Person x, Person y)
{
return Equals(x, y);
}
public static bool operator !=(Person x, Person y)
{
return !Equals(x, y);
}
public override bool Equals(object y)
{
return Equals(this, y as Person);
}
public bool Equals(Person y)
{
return Equals(this, y);
}
请注意,我的方式比您教授的方式更加优雅和清晰。请注意,我的方式处理 nullthis
而不this
直接与 null 进行比较。
再一次:所有这些都说明了折衷的立场,其中值和引用相等都是可能的,并且有四种(、、==
和)实现相等的方法,即使不假设can 或 not也是非常复杂和混乱的。!=
object.Equals(object)
IEquatable<T>.Equals(T)
this
null
如果你对这个主题感兴趣,我本周在我的博客上描述了一个稍微困难的问题:如何实现一般的比较,包括不等式。
http://ericlippert.com/2013/10/07/math-from-scratch-part-six-comparisons/
作为对 C# 如何处理相等性的批评,这些评论特别有趣。
最后:不要忘记覆盖GetHashCode
. 确保你做对了。