C# 调用IEquatable的结果<;T>;。当this==null且obj==null时等于(T obj)?

C# 调用IEquatable的结果<;T>;。当this==null且obj==null时等于(T obj)?,c#,.net,f#,equals,equality,C#,.net,F#,Equals,Equality,当this==null和obj==null时,IEquatable.Equals(T obj)应该做什么 1)此代码由F编译器在实现IEquatable时生成。您可以看到,当两个对象都为null时,它返回true: public sealed override bool Equals(T obj) { if (this == null) { return obj == null; } if (obj

this==null
obj==null
时,
IEquatable.Equals(T obj)
应该做什么

1)此代码由F编译器在实现
IEquatable
时生成。您可以看到,当两个对象都为
null
时,它返回
true

public sealed override bool Equals(T obj) { if (this == null) { return obj == null; } if (obj == null) { return false; } // Code when both this and obj are not null. }
3)最后一个选项是,当
this==null
时,方法的行为没有定义。我会选择选项1:

    if (this == null)
    {
        return obj == null;
    }
    if (obj == null)
    {
        return false;
    }

null对象始终等于null对象。

示例代码在MSDN中:

如果此==null,您将在该对象上获得调用equals()的运行时异常。

如果
为null,则无法调用代码,因此无需考虑这种情况(无论如何,在C#中,有些情况下,语言允许空对象取消引用方法,尽管很明显,如果它在内部检查任何不存在的字段,它将出错。请考虑:

return x.Equals(y);
如果x为null,我们甚至不能调用
Equals
来计算null检查

因此,我们只需考虑:

public bool Equals(T obj)
{
  if(obj == null)
    return false;
  //logic defining equality here.
}
当我们从静态
=
操作符覆盖或从
IEqualityComparer
实现中检查它们时,两个对象都可能为空:

public bool Equals(T x, T y)
{
  if(x == null)
    return y == null;
  if(y == null)
    return false;
  //logic defining equality here.
}
请注意,这里有一个有用的快捷方式,如果相等可以很长时间来确定(例如,比较长字符串),那么我们可以利用一个事实,即身份意味着相等-这是一个总是等于自身的东西,即使Ayn Rand也能解出这一点;)还有一些算法使得将项目与自身进行比较变得非常常见,这使得此快捷方式非常值得包括在内。在这种情况下,身份比较已经包括检查两者是否为null,因此我们再次省略它:

public bool Equals(T x, T y)
{
  if(ReferenceEquals(x, y))
    return true;
  if(x == null || y == null)
    return false;
  //logic defining equality here.
}

对于大多数方法,当使用
this==null
调用时,我假设未定义的行为。这是因为大多数程序员都是在
this!=null
的假设下编写代码的,如果调用代码是用C编写的,那么C规范保证了这一点

这就是为什么
x.Equals(y)
的每个正常调用方都应该知道
x
不是
null
,或者添加手动
null
检查

在大多数情况下,我根本不会直接调用
Equals
,而是使用
EqualityComparer.Default

F#这样做的原因(我怀疑)是将空列表优化为
null

通过添加此检查,可以在
null
实例上调用实例方法,而不会出现任何问题

从不久前开始看

在C#中,这是不相关的

回答问题:


它应该返回
true
,因为这两个实例都是
null
,并且被认为是相等的。

leppie是对的。请详细说明他的答案(并证实他怀疑F#不能保证
this!=null)
:有区别的联合可以用属性
[]
允许案例由值null表示。就是这样一种类型。
案例在运行时由null表示。
(无:选项)。等于(无)
在语法上是有效的。下面是一个有趣的示例:

[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type Maybe<'T> =
  | Just of 'T
  | Nothing
  [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
  member this.ThisIsNull() = match this with Nothing -> true | _ -> false
结果是:

Nothing.ThisIsNull() //true

案例
this==null
不应该(!!!)发生。不确定F的特性,但在C中,这是成立的。当方法由
call
opcode调用时,没有检查
this!=null
。@RadekMicek,这就是为什么C编译器为非静态方法调用发出
callvirt
。但也许F只发出
call
。@Radek即使如此,上述情况也不会发生“在C#中永远不会是正确的语义,这种情况下也不需要检查
null
。即使在VB中,它有一个
MyClass
关键字,它发出一个
call
而不是
callvirt
,这种情况也不会发生。@KonradRudolph:但在CLR中仍然可能…
this
不能为null;为了o有权访问
,您必须在类型的实例中,我当然知道,但此==null从来没有意义,因为您在到达该位置之前会遇到运行时异常。@Jobo-唯一可能的异常是StackOverflowException。这就是您所指的吗?
此!=null
仅在您能够ll直接使用C#(可能还有大多数其他.net语言)的方法。可以从其他语言或使用委托调用带有
this==null
的实例方法。
this
可以是
null
,只是在C中不可以。但这永远不等于null。@Jonhana,在C中,这是正确的,但OP显示的代码是由F#生成的(可能由Reflector或类似工具反编译为C#)@是的,这就是为什么他们要问这个问题,但是把它留在工程C#中是没有意义的。在C#(如标签所示)中,测试不可能是真的。@Jonhana,当然,但是如果这个方法是用C#编写的,并且被另一种语言的代码调用,在调用该方法之前不检查null,那该怎么办?(例如,如果它发出
call
而不是
callvirt
)@ThomasLevesque会不会在检查成员以更详细地检查平等性时立即抛出?就像对一个方法使用
调用
一样,如果该方法在对象为null的情况下不能保证表现良好,那么无论使用何种语言,它都可以做到这一点。IMO该代码示例非常可疑。可变id实体和不比较所有公共属性都是我要避免的模式。C#保证这一点,F#不是我假设的。请参阅我的答案。但F#中的空列表定义为非null
内部静态只读FSharpList _unique_empty=new FSharpList()
正如其他人所指出的,
null
不用作F#中空列表的表示形式。但是,它用作
public bool ThisIsNull()
{
    return (this == null);
}
Nothing.ThisIsNull() //true