简体   繁体   English

C#等式检查

[英]C# equality checking

What's your approach on writing equality checks for the structs and classes you create? 您为自己创建的structsclasses编写相等性检查的方法是什么?

1) Does the "full" equality checking require that much of boilerplate code (like override Equals , override GetHashCode , generic Equals , operator== , operator!= )? 1) “完全”等式检查是否需要大量样板代码(如override Equalsoverride GetHashCode ,泛型Equalsoperator==operator!= )?

2) Do you specify explicitly that your classes model the IEquatable<T> interface? 2)您是否明确指定您的类为IEquatable<T>接口建模?

3) Do I understand correctly, that there is no actual way to automatically apply Equals overrides, when I invoke something like a == b and I always have to implement both the Equals and operator== members? 3)我是否理解正确,没有实际的方法来自动应用Equals覆盖,当我调用类似a == b东西时,我总是要实现Equalsoperator==成员?

You're right, this is a lot of boiler-plate code, and you need to implement everything separately. 你是对的,这是很多样板代码,你需要单独实现所有东西。

I would recommend: 我建议:

  • If you're going to implement value equality at all, override GetHashCode and Equals(object) - creating overloads for == and implementing IEquatable<T> without doing that could result in very unexpected behaviour 如果你要实现值相等,重写GetHashCodeEquals(object) - 为==创建重载并实现IEquatable<T>而不这样做可能会导致非常意外的行为
  • I would always implement IEquatable<T> if you're overriding Equals(object) and GetHashCode 如果你要覆盖Equals(object)GetHashCode我总是会实现IEquatable<T>
  • I only overload the == operator more rarely 我只是很少重载==运算符
  • Implementing equality correctly for unsealed classes is tricky, and can still produce surprising/undesirable results. 正确地为未密封的类实现相等性是棘手的,并且仍然可以产生令人惊讶的/不期望的结果。 If you need equality for types in a hierarchy, implement IEqualityComparer<T> expressing the comparison you're interested in. 如果层次结构中的类型需要相等,请实现表达您感兴趣的比较的IEqualityComparer<T>
  • Equality for mutable types is usually a bad idea, as two objects can be equal and then unequal later... if an object is mutated (in an equality-affecting way) after it's been used as a key in a hash table, you won't be able to find it again. 可变类型的平等通常是一个坏主意,因为两个对象可以相等然后不等...如果一个对象在被用作哈希表中的键之后被变异(以相等的方式),你赢了再也找不到了。
  • Some of the boiler-plate is slightly different for structs... but like Marc, I very rarely write my own structs. 一些锅炉板的结构略有不同......但像Marc一样,我很少编写自己的结构。

Here's a sample implementation: 这是一个示例实现:

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);
    }
}

And yes, that's a heck of a lot of boilerplate, very little of which changes between implementations :( 是的,这是一个很多样板的问题,实现之间的变化很少:(

The implementation of == is slightly less efficient than it might be, as it will call through to Equals(object) which needs to do the dynamic type check... but the alternative is even more boiler-plate, like this: ==的实现效率稍差 ,因为它会调用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);
}

I rarely do anything special for classes; 我很少为课程做任何特别的事情; for most regular objects referential equality works fine. 对于大多数常规对象,引用平等工作正常。

I even more rarely write a struct ; 我甚至更少写一个struct ; but since structs represent values it is usually appropriate to provide equality etc. This would usually involve everything; 但由于结构代表价值 ,通常适当提供平等等。这通常涉及一切; Equals, ==, != and IEquatable<T> (since this avoids boxing in scenarios using EqualityComparer<T>.Default . Equals,==,!=和IEquatable<T> (因为这可以避免在使用EqualityComparer<T>.Default场景中进行装箱。

The boilerplate isn't usually too problematic, but IIRC tools like resharper can help here. 样板文件通常不会太成问题,但像resharper这样的IIRC工具可以在这里提供帮助。

Yes, it is advisable to keep Equals and == in sync, and this needs to be done explicitely. 是的,建议保持Equals和==同步,这需要明确地完成。

You just need to implement operator== for a==b . 你只需要为== b实现operator ==。
As I like my data in dictionaries sometimes I override GetHashCode. 由于我喜欢字典中的数据,有时候我会覆盖GetHashCode。
Next I implement Equals (as an unmentioned standard ... this is because there is no constraint for equality when using generics) and specify implementing IEquatable. 接下来我实现Equals(作为一个未提及的标准......这是因为在使用泛型时没有相等的约束)并指定实现IEquatable。 Since I am going to do this I might as well point my == and != implementations to Equals. 由于我要这样做,我不妨将我的==和!=实现指向Equals。 :) :)

See What is "Best Practice" For Comparing Two Instances of a Reference Type? 请参阅比较参考类型的两个实例的“最佳实践”是什么?

You can avoid boiler plate code (hope C#/VS team brings something easy for developers in their next iteration) with the help of a snippet, here is one such.. 您可以在一个片段的帮助下避免样板代码(希望C#/ VS团队在下一次迭代中为开发人员带来一些简单的东西), 这里有一个这样的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM