在Java中this是否可以为null我不知道.现在解决您有关C#的问题.假设==没有重载.我们待会儿会回到这一点.您的方法是用C#编写的.假设使用空接收器从C#程序调用它. C#编译器评估接收方是否可能为null.如果它可能为null,则确保它在调用该方法之前生成对代码进行空检查的代码.因此,在这种情况下,此检查毫无意义.当然,这是99.9999%的可能性.假设它是通过反射调用的,就像Mike Z的回答一样.在这种情况下,不是C#语言执行调用;而是使用C#语言执行调用.相反,有人故意滥用反射.假设它是从另一种语言调用的.我们有一个虚拟的方法;如果通过虚拟调度从另一种语言调用它,则必须执行空检查,因为否则我们怎么知道虚拟插槽中的内容呢?在那种情况下,它不能为空.但是假设它是使用非虚拟调度从另一种语言调用的.在这种情况下,另一种语言无需实现检查空值的C#功能.它可以调用它并传递null.因此,在C#中有几种方法可以将this用作null,但是它们全都超出了主流.因此,人们很少像您的教授那样编写代码. 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可以为null,好的,让我们开始吧. 阻止this.dni引发空引用异常的原因是什么??如果您要假设this可以为null,那么至少要始终如此! (在Coverity,我们将这种情况称为前向空缺".)下一步:我们要覆盖Equals,然后在内部使用==,大概是指引用相等. 这种方式掩盖了疯狂!现在,我们遇到的情况是x.Equals(y)可以为真,而x==y可以为假!这太可怕了.请不要去那里.如果要覆盖Equals,则同时重载==,并在执行时实现IEquatable<T>.(现在,有一个合理的论点是疯狂在任何一个方向上都存在;如果==与具有值语义的Equals一致,那么personx == persony可能与(object)personx == (object)persony不同,这似乎也很奇怪.这里的要点是,在C#中相当混乱了.)此外:如果==稍后被覆盖怎么办?现在,当代码的作者明确希望进行参考比较时,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);}请注意,我的方式比您教授的方式更加优雅和清晰.并请注意,我的方法无需直接将this与null进行比较就可以处理null this.再次:所有这些都表明折衷方案已经到来,在其中值和引用相等都是可能的,并且有四种(==,!=,object.Equals(object)和IEquatable<T>.Equals(T))实现相等的方法,即使不假设this可以或不能为null的情况,也非常复杂且令人困惑.如果您对此主题感兴趣,我将在本周的博客上描述一个稍微棘手的问题:如何实现一般的比较,包括不平等. http://ericlippert.com/2013 /10/07/math-from-scratch-part-six-comparisons/评论对C#如何处理平等特别有趣.最后:不要忘记覆盖GetHashCode. 请确保您这样做没错. In an example, my professor has implemented Equals as follows:public class Person { private string dni; // ... public override bool Equals(object o) { if (o == null) return (this == null); else { return ((o is Person) && (this.dni == (o as Person).dni)); } }}I have no experience with C#, but as far as I know this cannot be null inside a member function (at least this is true in C++ and Java, the languages I know) so the if seems weird to me.Am I right or is there any component in c# I dont know of which makes the test this == null necesary? 解决方案 Let's begin by noting that your statement is false.In C++, dispatching a method on a null receiver is undefined behavior and undefined behavior means that anything can happen. "Anything" includes the program passing NULL as this and continuing as though nothing was wrong. Of course it is somewhat silly to check whether this is null in C++ because the check can only be true if you already do not know what your program is doing, because its behavior is undefined.Whether this can be null in Java I have no idea.Now to address your question about C#. Let's assume that == is not overloaded. We'll come back to this point later.Your method is written in C#. Suppose it is invoked from a C# program with a null receiver. The C# compiler evaluates whether the receiver could possibly be null; if it could possibly be null then it ensures that it generates code that does a null check before invoking the method. Therefore this check is pointless in that scenario. This is of course the 99.9999% likely scenario.Suppose it is invoked via Reflection, as in mike z's answer. In that case it is not the C# language that is performing the invocation; rather, someone is deliberately abusing reflection.Suppose it is invoked from another language. We have a virtual method; if it is invoked from this other language with virtual dispatch then a null check must be performed, because how else could we know what is in the virtual slot? In that scenario it cannot be null.But suppose it is invoked from another language using non-virtual dispatch. In that case the other language need not implement the C# feature of checking for null. It could just invoke it and pass null.So there are several ways in which this could be null in C#, but they are all very much out of the mainstream. It is therefore very rare for people to write code as your professor has. C# programmers idiomatically suppose that this is not null and never check for it.Now that we've gotten that out of the way, let's criticize that code some more.public override bool Equals(object o) { if (o == null) return (this == null); else { return ((o is Person) && (this.dni == (o as Person).dni)); }}First off there is an obvious bug. We presume that this could be null, ok, let's run with that. What stops this.dni from throwing null reference exception??? If you're going to assume that this can be null then at least do so consistently! (At Coverity we refer to this sort of situation as a "forward null defect".)Next: we are overriding Equals and then using == inside, presumably to mean reference equality. This way lies madness! Now we have a situation where x.Equals(y) can be true but x==y can be false! This is horrid. Please don't go there. If you're going to override Equals then overload == at the same time, and implement IEquatable<T> while you're at it.(Now, there is a reasonable argument to be made that madness lies in either direction; if == is consistent with Equals with value semantics then personx == persony can be different than (object)personx == (object)persony, which seems strange also. The takeaway here is that equality is pretty messed up in C#.)Moreover: what if == is overridden later? Now Equals is calling an overridden == operator, when the author of the code clearly wishes to be doing a reference comparison. This is a recipe for bugs.My recommendations are (1) write one static method that does the right thing, and (2) use ReferenceEquals every time there could possibly be any confusion over what kind of equality is meant: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;}That nicely covers every case. Notice that it is crystal clear to the reader when reference equality semantics are meant. Also note that this code makes it very easy to put breakpoints on each possibility, for debugging purposes. And finally, notice that we take the cheapest possible early out; if the objects are reference equal then we don't have to do the potentially expensive comparison of the fields!Now the other methods are easy: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);}Notice how much more elegant and clear my way is than your professor's way. And notice that my way handles a null this without ever comparing this to null directly.Again: all of this illustrates that the compromise position arrived at, in which both value and reference equality are possible and there are four (==, !=, object.Equals(object) and IEquatable<T>.Equals(T)) ways to implement equality, is very complicated and confusing even without assuming that this can or cannot be null.If this subject interests you, I describe a slightly harder problem on my blog this week: how to implement comparisons in general, including inequalities.http://ericlippert.com/2013/10/07/math-from-scratch-part-six-comparisons/The comments are particularly interesting as a critique of how C# handles equality.Finally: don't forget to override GetHashCode. Make sure you do it right. 这篇关于'this'关键字是否可以等于null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-27 16:30