C# 使用“as”重写等于 以及正确性、灵活性和性能的专门方法

发布于 2024-07-11 19:44:56 字数 1387 浏览 11 评论 0原文

我想知道在 C# 中实现正确、灵活和快速的 Equals 的最佳方法,它几乎可以用于任何类和情况。 我认为需要一个专门的 Equals (将实际类的对象作为参数)来提高性能。 为了避免代码重复,通用的 Equals 应该调用专用的 Equals。 即使在继承的类中,空检查也应该只执行一次。

我最终想出了这个设计:


class MyClass
{
    public Int32 SomeValue1 = 1;
    public Int32 SomeValue2 = 25;

    // Ignoring GetHashCode for simplicity.

    public override bool Equals(object obj)
    {
        return Equals (obj as MyClass);
    }

    public bool Equals(MyClass obj)
    {
        if (obj == null) {
            return false;
        }

        if (!SomeValue1.Equals (obj.SomeValue1)) {
            return false;
        }

        if (!SomeValue2.Equals (obj.SomeValue2)) {
            return false;
        }

        return true;
    }
}

class MyDerivedClass : MyClass
{
    public Int32 YetAnotherValue = 2;

    public override bool Equals(object obj)
    {
        return Equals (obj as MyDerivedClass);
    }

    public bool Equals(MyDerivedClass obj)
    {
        if (!base.Equals (obj)) {
            return false;
        }

        if (!YetAnotherValue.Equals (obj.YetAnotherValue)) {
            return false;
        }

        return true;
    }
}

重要想法:

  • “as”运算符的用法。 这样我们就不必检查一般 Equals 中的空值。 错误的类类型会减少为 null,并将在专门的 Equals 中进行排序。
  • 即使对于派生类,也只在某一点进行 Null 检查。
  • 依次检查属性可以提供清晰的结构。

这个概念是否存在缺陷,或者我错过了任何条件?

I wondered about the best way to implement a correct, flexible and fast Equals in C#, that can be used for practically any class and situation. I figured that a specialized Equals (taking an object of the actual class as parameter) is needed for performance. To avoid code duplication, the general Equals ought to call the specialized Equals. Null checks should be performed only once, even in inherited classes.

I finally came up with this design:


class MyClass
{
    public Int32 SomeValue1 = 1;
    public Int32 SomeValue2 = 25;

    // Ignoring GetHashCode for simplicity.

    public override bool Equals(object obj)
    {
        return Equals (obj as MyClass);
    }

    public bool Equals(MyClass obj)
    {
        if (obj == null) {
            return false;
        }

        if (!SomeValue1.Equals (obj.SomeValue1)) {
            return false;
        }

        if (!SomeValue2.Equals (obj.SomeValue2)) {
            return false;
        }

        return true;
    }
}

class MyDerivedClass : MyClass
{
    public Int32 YetAnotherValue = 2;

    public override bool Equals(object obj)
    {
        return Equals (obj as MyDerivedClass);
    }

    public bool Equals(MyDerivedClass obj)
    {
        if (!base.Equals (obj)) {
            return false;
        }

        if (!YetAnotherValue.Equals (obj.YetAnotherValue)) {
            return false;
        }

        return true;
    }
}

Important ideas:

  • Usage of the "as" operator. This way we don't have to check for nulls in the general Equals. Wrong class types get reduced to null and will be sorted out in the specialized Equals.
  • Null check at exactly one point, even for derived classes.
  • Checking the attributes one after another provides a clear structure.

Are there flaws in this concepts, or did i miss any conditions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

机场等船 2024-07-18 19:44:56

当涉及不同类型时,您的 Equals 方法不是自反的:

MyDerivedClass mdc = new MyDerivedClass();
MyClass mc = new MyClass();
Object omdc = mdc;
Object omc = mc;

// mc.Equals(mdc) - true
// mdc.Equals(mc) - true by calling the right overload
// omc.Equals(omdc) - true
// omdc.Equals(omc) - false, the "as" in MyDerivedClass will result in null

解决此问题的正常方法是使用:

if (GetType() != other.GetType())
{
    return false;
}

请参阅 Object.Equals: "x.Equals(y) 返回与 y.Equals(x) 相同的值。"
依靠重载来给出不同的结果可能会导致可怕的问题,而这些问题对于调试来说是非常微妙的。

Your Equals method isn't reflexive when different types are involved:

MyDerivedClass mdc = new MyDerivedClass();
MyClass mc = new MyClass();
Object omdc = mdc;
Object omc = mc;

// mc.Equals(mdc) - true
// mdc.Equals(mc) - true by calling the right overload
// omc.Equals(omdc) - true
// omdc.Equals(omc) - false, the "as" in MyDerivedClass will result in null

The normal way round this is to use:

if (GetType() != other.GetType())
{
    return false;
}

See the docs in Object.Equals: "x.Equals(y) returns the same value as y.Equals(x)."
Relying on overloading to give different results could end up with horribly issues which would be very subtle to debug.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文