C#等式检查

时间:2010-12-12 08:52:43

标签: c# equality

您为所创建的structsclasses撰写平等检查的方法是什么?

1)“完整”等式检查是否需要大量样板代码(例如override Equalsoverride GetHashCode,通用Equals,{{1} },operator==)?

2)您是否明确指定您的类为operator!=界面建模?

3)我是否理解正确,当我调用类似IEquatable<T>的内容时,没有实际的方法可以自动应用Equals覆盖,而且我总是必须实现这两种覆盖a == bEquals成员?

4 个答案:

答案 0 :(得分:20)

你是对的,这是很多样板代码,你需要单独实现所有内容。

我建议:

  • 如果您要实现值相等,请覆盖GetHashCodeEquals(object) - 为==创建重载并实现IEquatable<T>而不执行此操作可能会导致非常意外的行为< / LI>
  • 如果您覆盖IEquatable<T>Equals(object)
  • ,我会始终实施GetHashCode
  • 我只是很少重载==运算符
  • 对于未密封的类正确实现相等性是棘手的,并且仍然可能产生令人惊讶的/不期望的结果。如果层次结构中的类型需要相等,请实现表达您感兴趣的比较的IEqualityComparer<T>
  • 可变类型的平等通常是一个坏主意,因为两个对象可以相等然后不等...如果一个对象在被用作哈希表中的键之后发生变异(以相同的方式影响) ,你将无法再找到它。
  • 一些锅炉板的结构略有不同......但是像Marc一样,我很少写自己的结构。

以下是一个示例实现:

using System;

public sealed class Foo : IEquatable<Foo>
{
    private readonly string name;
    public string Name { get { return name; } }

    private readonly int value;
    public int Value { get { return value; } }

    public Foo(string name, int value)
    {
        this.name = name;
        this.value = value;
    }

    public override bool Equals(object other)
    {
        return Equals(other as Foo);
    }

    public override int GetHashCode()
    {
        int hash = 17;
        hash = hash * 31 + (name == null ? 0 : name.GetHashCode());
        hash = hash * 31 + value;
        return hash;
    }

    public bool Equals(Foo other)
    {
        if ((object) other == null)
        {
            return false;
        }
        return name == other.name && value == other.value;
    }

    public static bool operator ==(Foo left, Foo right)
    {
        return object.Equals(left, right);
    }

    public static bool operator !=(Foo left, Foo right)
    {
        return !(left == right);
    }
}

是的,这是很多样板文件,实现之间的变化很小:(

==的实施稍微效率低,因为它会调用Equals(object),需要进行动态类型检查...但是替代方案更像是锅炉板,如下:

public static bool operator ==(Foo left, Foo right)
{
    if ((object) left == (object) right)
    {
        return true;
    }

    // "right" being null is covered in left.Equals(right)
    if ((object) left == null)
    {
        return false;
    }
    return left.Equals(right);
}

答案 1 :(得分:6)

我很少为课程做任何特别的事情;对于大多数常规对象,引用平等工作正常。

我甚至更少写struct;但由于结构代表,通常适合提供平等等。这通常涉及一切;等于,==,!=和IEquatable<T>(因为这可以避免使用EqualityComparer<T>.Default进行装箱。

样板文件通常不会太成问题,但像resharper这样的IIRC工具可以在这里提供帮助。

是的,建议保持Equals和==同步,这需要明确地完成。

答案 2 :(得分:1)

你只需要为== b实现operator ==。
由于我喜欢字典中的数据,有时候我会覆盖GetHashCode。
接下来我实现Equals(作为一个未提及的标准......这是因为在使用泛型时没有相等的约束)并指定实现IEquatable。由于我要这样做,我不妨将我的==和!=实现指向Equals。 :)

答案 3 :(得分:0)

请参阅What is "Best Practice" For Comparing Two Instances of a Reference Type?

借助代码段here is one such..

,您可以避免使用样板代码(希望C#/ VS团队在下一次迭代中为开发人员带来一些便利)