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