【问题标题】:How to Implement IEquatable with Different Equality Checks如何使用不同的等式检查实现 IEquatable
【发布时间】:2020-03-12 14:13:43
【问题描述】:

我有一个 MyCustomSet 类,其中 IEquatable 实现如下所示。

当我想检查所有三个集合(SetA*、SetB* 和 SetC*)的相等性时,这非常有用。但是要求要求我还需要能够检查仅 SetA*、SetB* 或 SetC* 或其组合(SetA* 和 SetB*、SetA* 和 SetC*、或 SetB* 和 SetC*)的相等性并忽略检查检查中不需要的任何其他 Set 的相等性。

目前,我正在使用 foreach 和 LINQ 来遍历 Set 以执行部分​​相等性检查,这很有效,但对于大型数据集。

也许答案是直视我的脸,但我看不到它,因为我不知道如何实现可以处理的 IEquatable不同的相等性检查。

是否有人可以就如何实施提供一些建议或指导?一个例子会更受欢迎。

public static class HashCode
{
    public const int Start = 17;

    public static int Hash<T>(this int hash, T obj)
    {
        var h = EqualityComparer<T>.Default.GetHashCode(obj);
        return unchecked((hash * 439) + h);
    }
}

public class MyCustomSetModel
{
    public sealed class MyCustomSet : IEquatable<MyCustomSet>
    {
        public string ItemName { get; set; }
        public string ItemType { get; set; }

        public double SetA1 { get; set; }
        public double SetA2 { get; set; }
        public double SetA3 { get; set; }

        public double SetB1 { get; set; }
        public double SetB2 { get; set; }
        public double SetB3 { get; set; }

        public double SetC1 { get; set; }
        public double SetC2 { get; set; }
        public double SetC3 { get; set; }

        public bool Equals(MyCustomSet other)
        {
            if (ReferenceEquals(other, null))
            {
                return false;
            }

            if (ReferenceEquals(other, this))
            {
                return true;
            }

            return
                (
                (this.ItemName == other.ItemName) &&
                (this.ItemType == other.ItemType) &&

                (this.SetA1 == other.SetA1) &&
                (this.SetA2 == other.SetA2) &&
                (this.SetA3 == other.SetA3) &&

                (this.SetB1 == other.SetB1) &&
                (this.SetB2 == other.SetB2) &&
                (this.SetB3 == other.SetB3) &&

                (this.SetC1 == other.SetC1) &&
                (this.SetC2 == other.SetC2) &&
                (this.SetC3 == other.SetC3)
                );
        }

        public override bool Equals(object obj) => Equals(obj as MyCustomSet);

        public override int GetHashCode()
        {
            unchecked
            {
                return HashCode.Start
                    .Hash(ItemName)
                    .Hash(ItemType)

                    .Hash(SetA1)
                    .Hash(SetA2)
                    .Hash(SetA3)

                    .Hash(SetB1)
                    .Hash(SetB2)
                    .Hash(SetB3)

                    .Hash(SetC1)
                    .Hash(SetC2)
                    .Hash(SetC3);
            }
        }
    }
}

* 更新:*

感谢 Matthew Watson 为我指明了正确的方向。所以我实现了一个自定义比较器,如下所示。看起来它正在运行,但如果有人看到潜在的问题或更好的实施空间,请随时发表评论。

        public sealed class MyCustomSetComparer : IEqualityComparer<MyCustomSet>
        {
            private bool _compareSetA;
            private bool _compareSetB;
            private bool _compareSetC;

            public MyCustomSetComparer(bool compareSetA = true, bool compareSetB = true, bool compareSetC = true)
            {
                _compareSetA = compareSetA;
                _compareSetB = compareSetB;
                _compareSetC = compareSetC;
            }

            public bool Equals(MyCustomSet x, MyCustomSet y)
            {
                if (Object.ReferenceEquals(x, y))
                {
                    return true;
                }

                if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                {
                    return false;
                }

                bool result =
                    (x.ItemName == y.ItemName) &&
                    (x.ItemType == y.ItemType);

                if (_compareSetA)
                {
                    result = result &&
                        (x.SetA1 == y.SetA1) &&
                        (x.SetA2 == y.SetA2) &&
                        (x.SetA3 == y.SetA3);
                }

                if (_compareSetB)
                {
                    result = result &&
                        (x.SetB1 == y.SetB1) &&
                        (x.SetB2 == y.SetB2) &&
                        (x.SetB3 == y.SetB3);
                }

                if (_compareSetC)
                {
                    result = result &&
                        (x.SetC1 == y.SetC1) &&
                        (x.SetC2 == y.SetC2) &&
                        (x.SetC3 == y.SetC3);
                }

                return result;
            }

            public int GetHashCode(MyCustomSet item)
            {
                if (Object.ReferenceEquals(item, null))
                {
                    return 0;
                }

                int hash = HashCode.Start
                    .Hash(item.ItemName)
                    .Hash(item.ItemType);

                if (_compareSetA)
                {
                    hash = hash.Hash(item.SetA1)
                        .Hash(item.SetA2)
                        .Hash(item.SetA3);
                }

                if (_compareSetB)
                {
                    hash = hash.Hash(item.SetB1)
                        .Hash(item.SetB2)
                        .Hash(item.SetB3);
                }

                if (_compareSetC)
                {
                    hash = hash.Hash(item.SetC1)
                        .Hash(item.SetC2)
                        .Hash(item.SetC3);
                }

                unchecked
                {
                    return hash;
                }
            }
        }

【问题讨论】:

  • 您的数据集有多大,需要多长时间?
  • 您应该查看IEqualityComparer&lt;MyCustomSet&gt; 的多个实现,然后使用accept a parameter of type IEqualityComparer&lt;T&gt; 的各种Linq 方法的重载,这样您就可以从被比较对象的实现外部控制比较。跨度>

标签: c# equality iequalitycomparer iequatable


【解决方案1】:

根据 Matthew Watson 的评论,这是使用 IEqualityComparer&lt;T&gt; 而不是 IEquatable&lt;T&gt; 的最佳时机。我建议仅在类型有一个明显的、自然的相等定义时才实现IEquatable&lt;T&gt;。当有多个相等选项且没有一个选项比其他选项更合理时,请实现 IEqualityComparer&lt;T&gt; - 在几种不同的实现类型中,或者在根据创建参数化的单个实现类型中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多