Rop*_*tah 8 .net c# stack-overflow operator-overloading
请在下面的代码中查看我的评论.我应该如何检查参数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;
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 27
为什么会这样?
因为语言规则说.
您已向运营商提供此签名:
public static bool operator ==(Foo f1, Foo f2)
Run Code Online (Sandbox Code Playgroud)
然后 - 无论发生在代码中的哪个地方 - 你都有这个表达式:
f1 == null
Run Code Online (Sandbox Code Playgroud)
其中f1编译时类型为Foo.现在null也可以隐式转换Foo,为什么不使用你的运算符?如果你的操作员的第一行无条件地调用自己,你应该期待堆栈溢出......
为了不发生这种情况,您需要对语言进行两项更改之一:
==才能在声明中使用==.伊克.==带有一个操作数的表达式null 总是意味着参考比较.IMO也不是特别好.避免它很简单,避免冗余,并添加优化:
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);
}
Run Code Online (Sandbox Code Playgroud)
但是,你则需要修正你的Equals方法,因为这则结束调用回你的==,导致另一堆栈溢出.你实际上从未真正说过你希望如何确定平等......
我通常会有这样的事情:
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这使您只能在一个地方进行无效检查.为了避免f1在通过开始的实例方法调用null时冗余地比较null Equals,你可以在检查无效之后委托==给,但我可能会坚持这样做.Equalsf1