请在下面的代码中查看我的评论。我应该如何检查参数是否为 null
?看起来 null
被转换为 Foo
,这实际上对 ==
运算符进行了递归调用。为什么会这样?
public class Foo
{
public static bool operator ==(Foo f1, Foo f2)
{
if (f1 == null) //This throw a StackOverflowException
return f2 == null;
if (f2 == null)
return f1 == null;
else
return f1.Equals((object)f2);
}
public static bool operator !=(Foo f1, Foo f2)
{
return !(f1 == f2);
}
public override bool Equals(object obj)
{
Foo f = obj as Foo;
if (f == (Foo)null)
return false;
return false;
}
public override int GetHashCode()
{
return 0;
}
}
最佳答案
Why does this happen?
因为语言规则说到。
您已向运算符(operator)提供此签名:
public static bool operator ==(Foo f1, Foo f2)
然后 - 无论这发生在代码中 - 你都会得到这个表达式:
f1 == null
其中 f1
的编译时类型为 Foo
。现在 null
也可以隐式转换为 Foo
,那么为什么不会它使用您的运算符?如果您的运算符的第一行无条件地调用自身,您应该期待堆栈溢出...
为了不发生这种情况,您需要对语言进行以下两项更改之一:
- 当在
==
的声明中使用时,该语言必须对==
的含义进行特殊处理。恶心。 - 语言必须决定任何一个操作数为
null
的==
表达式 始终 表示引用比较。
在我看来,两者都不是特别好。避免它很简单,避免冗余,并添加优化:
public static bool operator ==(Foo f1, Foo f2)
{
if (object.ReferenceEquals(f1, f2))
{
return true;
}
if (object.ReferenceEquals(f1, null) ||
object.ReferenceEquals(f2, null))
{
return false;
}
return f1.Equals(f2);
}
但是,您然后需要修复您的Equals
方法,因为这最终会回调到您的==
,从而导致< em>另一个 堆栈溢出。您从未实际上说出您希望如何确定平等...
我通常会有这样的东西:
// Where possible, define equality on sealed types.
// It gets messier otherwise...
public sealed class Foo : IEquatable<Foo>
{
public static bool operator ==(Foo f1, Foo f2)
{
if (object.ReferenceEquals(f1, f2))
{
return true;
}
if (object.ReferenceEquals(f1, null) ||
object.ReferenceEquals(f2, null))
{
return false;
}
// Perform actual equality check here
}
public override bool Equals(object other)
{
return this == (other as Foo);
}
public bool Equals(Foo other)
{
return this == other;
}
public static bool operator !=(Foo f1, Foo f2)
{
return !(f1 == f2);
}
public override int GetHashCode()
{
// Compute hash code here
}
}
请注意,这让您只需在一个地方进行无效检查。为了避免在通过 Equals
的实例方法调用时将 f1
冗余地与 null 进行比较,您可以从 ==
在检查 f1
是否为空后变为 Equals
,但我可能会坚持这样做。
关于c# - 为什么在此运算符定义中抛出 stackoverflowexception?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9656040/