简体   繁体   English

等于与另一个可空类型上的可空类型进行比较

[英]Equals comparison with a nullable type on another nullable type

I have two objects(of the same type) which contains a prop myprop of type byte?我有两个对象(相同类型),其中包含一个myprop类型的 prop myprop byte? . . The properties are set to null .属性设置为null When I perform objectA.myprop.Equals(objectB.myprop) I get 'true' as a result although the MSDN code sample states that "Equals applied to any null object returns false."当我执行objectA.myprop.Equals(objectB.myprop)尽管MSDN代码示例指出“应用于任何空对象的等于返回 false”,但结果是“真”。

I'm guessing C# uses a seperate overload for nullable type comparisons.我猜 C# 使用单独的重载进行可空类型比较。 I would like to know how C# internally treats objects versus nullable types in this case.在这种情况下,我想知道 C# 如何在内部处理对象与可空类型。

When you call it like that, it will use Nullable<T>.Equals(object) which shows the expected behaviour in the documentation:当你这样称呼它时,它将使用Nullable<T>.Equals(object) ,它显示了文档中的预期行为:

(Return value is true if...) (如果……返回值为true

The HasValue property is false, and the other parameter is null . HasValue属性为 false,另一个参数为null That is, two null values are equal by definition.也就是说,根据定义,两个空值是相等的。

Likewise for equality via == , section 7.3.7 of the C# 4 spec (lifted operators) states:同样,对于通过==实现的相等性,C# 4 规范(提升运算符)的第 7.3.7 节指出:

For the equality operators == [and] != a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool.对于相等运算符== [and] !=如果操作数类型都是不可为 null 的值类型并且结果类型为 bool,则存在运算符的提升形式。 The lifted form is constructed by adding a single ?提升的形式是通过添加一个 ? modifier to each operand type.每个操作数类型的修饰符。 The lifted operator considers two null values equal , and a null value unequal to any non-null value.提升运算符认为两个空值相等,空值不等于任何非空值。 If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.如果两个操作数都不为空,则提升的运算符解开操作数并应用基础运算符以生成 bool 结果。

(Emphasis mine.) (强调我的。)

EDIT: Now I actually disagree with the accepted answer here, where it says it's not a general rule.编辑:现在我实际上不同意这里接受的答案,它说这不是一般规则。 It is a general rule, in terms of the implementation of object.Equals :object.Equals的实现而言,这一个通用规则:

The following statements must be true for all implementations of the Equals method.对于 Equals 方法的所有实现,以下语句必须为真。 In the list, x, y, and z represent object references that are not null.在列表中,x、y 和 z 表示不为空的对象引用。

[...] [...]

  • x.Equals(null) returns false. x.Equals(null)返回 false。

So while it is a general rule, it doesn't apply in this specific case - because the value here isn't an object reference - it's a value type value .因此,虽然这一条通用规则,但它不适用于这种特定情况——因为这里的值不是对象引用——它是一个值类型 value It's still somewhat surprising, unless you basically accept that Nullable<T> is a bit of a special case - it has specific C# compiler support and it has CLR support in terms of boxing and unboxing.这仍然有点令人惊讶,除非您基本上接受Nullable<T>是一个特殊情况 - 它具有特定的 C# 编译器支持,并且在装箱和拆箱方面具有 CLR 支持。

I have edited this for clarity.为了清楚起见,我已经编辑了这个。

You misunderstood that quote.你误解了那句话。 To give the full context:给出完整的上下文:

string s = null;
string t = String.Empty; // Logically the same as ""

// Equals applied to any null object returns false.
bool b = (t.Equals(s));

This is saying that a reference to a string object does not equate to a null reference.这就是说对string对象的引用不等同于null引用。 You took that quote out of context, and interpreted it as a general rule, which it is not.您断章取意地引用了这句话,并将其解释为一般规则,但事实并非如此。 However this is referring to references NOT nullable types.然而,这是指引用不可为空的类型。

When you are dealing with nullable primitive types:当您处理可为空的原始类型时:

The actual rule is实际规则是

An equality comparison of two nullable types that are both null evaluates to true.两个都为 null 的可为 null 的类型的相等比较计算结果为 true。

http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

Nullable type is a struct and a struct never get a null value, so when a nullable type equals with null, this is means that this variable not really null rather a implicit cast occurred and that variable cast to a value type(nullable) with property Value=null .可空类型是一个结构和结构永远不会得到一个空值,所以当可空类型与空等于,这意味着这个变量不是真的空,而发生了隐式转换和变量强制转换为数值型(可为空)与属性值=空 So:所以:

int? a=null;//(a) get a memory space with value property = null
a.GetHashcode();//if (a) really is null must throw a exception but not throw 

I would claim that Nullable comparison X==Y behave exactly as should intuitively be expected, but I sense a possible misunderstanding here regarding X.Equals(Y) , which behaves as if it is a static method call.我会声称Nullable比较X==Y行为完全符合直觉上的预期,但我感觉到这里可能对X.Equals(Y)误解,它的行为就像是一个static方法调用。

object A, B;
MyStruct? X, Y;

The quote "Equals applied to any null object returns false."引用“应用于任何空对象的等于返回 false”。 is true for the non-static method A.Equals(B) , and should typically hold for any sensible overrides of it.对于非静态方法A.Equals(B)是正确的,并且通常应该适用于它的任何合理覆盖。

However, the only reason this is so, is because A.Equals is a non-static method belonging to A , meaning A can never be null .但是,唯一的原因是A.Equals是属于A非静态方法,这意味着A永远不能为null Attempting A.Equals(B) with A = null would indeed throw a NullReferenceException .尝试使用A = null A.Equals(B)确实会抛出NullReferenceException

The reason this has to be so is that the instance referred to by A might be of a more specific type than the declared variable A , and this more specific type might in turn override the A.Equals method.这样做的原因是A引用实例可能是比声明的变量A更具体的类型,而这个更具体的类型可能反过来覆盖A.Equals方法。 In other words, if A is null, then the runtime have no idea which implementation of A.Equals to use, and must therefore throw an Exception .换句话说,如果A为空,则运行时不知道要使用A.Equals哪个实现,因此必须抛出Exception

However static methods can't be overridden, meaning A can be null because the method to run is known already at compile-time.然而,静态方法不能被覆盖,这意味着A可以null因为要运行的方法在编译时就已经知道了。 (This is why calling static methods is marginally faster than calling their non-static counterparts, and also why the compiler may decide to inline some static calls, but I am digressing.) (这就是为什么调用静态方法比调用它们的非静态方法要快一点,也是为什么编译器可能决定内联一些静态调用,但我离题了。)

So, for any static implementations both operands can be null .因此,对于任何静态实现,两个操作数都可以为null Also, null should always be considered the same as null , and different from any other value.此外,应始终将null视为与null相同,并且与任何其他值不同。 (If an implementation of Equals deviates from this common assumption, then that will typically be considered a bug.) (如果Equals的实现偏离了这个常见的假设,那么这通常会被认为是一个错误。)

Examples of static Equals methods:静态Equals方法的示例:

A==B;
A!=B;
MyClass.Equals(A, B);
object.Equals(A, B);
ReferenceEquals(A, B);

In this regard Nullable behave the same way as objects.在这方面Nullable行为方式与对象相同。 The only difference being that X.Equals(Y) supports either X or Y or both to be null without throwing an Exception.唯一的区别是X.Equals(Y)支持 X 或 Y 或两者都为空而不抛出异常。 So it is more correct to say that it behaves like the static equality methods mentioned above, which is typically more desirable.因此,更正确地说它的行为类似于上面提到的静态相等方法,这通常更可取。

But how is it possible for X.Equals(Y) to behave like a static method?但是X.Equals(Y)怎么可能表现得像一个静态方法呢? This is because Nullable is a struct.这是因为Nullable是一个结构体。 Structs in C# does not support inheritance, so there is no difference between the type of the variable and the type of the instance. C#中的Structs不支持继承,所以变量的类型和实例的类型没有区别。 Which is why the runtime is never in doubt of which method Equals refers to.这就是为什么运行时永远不会怀疑 Equals 指的是哪个方法。 And so no Exception is needed.所以不需要异常。 Any value supported by the struct can therefore be supported by the method for both operands, and null is therefore just another value.因此,该结构支持的任何值都可以被两个操作数的方法支持,因此null只是另一个值。

Now, in addition to this there is some built-in special support for syntactical sugar and optimizations for Nullable types, but the behavior remains, as far as I know, as I described above.现在,除此之外,还有一些对Nullable类型的语法糖和优化的内置特殊支持,但据我所知,行为仍然存在,如上所述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM