c# - 为什么在此运算符定义中抛出 stackoverflowexception?

标签 c# .net operator-overloading stack-overflow

请在下面的代码中查看我的评论。我应该如何检查参数是否为 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/

相关文章:

c# - 从 .NET 4.5.2 项目访问 appsettings.json

c# - 在 DataGridView 中,在添加新行时将列的 ReadOnly 属性设置为 false,更新其 true (c#.net)

c# - 在 Windows 窗体中重新加载和刷新 Flash 文件

c# - 是一对一的关系糟糕的策略

c++ - 重载运算符%

c++ - 如何使operator=像operator+一样接受参数的导数?

java - 对于Android应用程序来说,c#好还是java好?

c# - IWizard 带有多项目模板来获取 nuget 预发布包

c# - 有没有办法将所有查询字符串名称/值对放入一个集合中?

c++ - 如何识别赋值运算符?