简体   繁体   English

如何使用不同的等式检查实现 IEquatable

[英]How to Implement IEquatable with Different Equality Checks

I have a MyCustomSet class with IEquatable implemented as shown below.我有一个带有IEquatableMyCustomSet类,如下所示。

This works fantastic when I want to check equality for all three sets (SetA*, SetB*, and SetC*).当我想检查所有三个集合(SetA*、SetB* 和 SetC*)的相等性时,这非常有效。 But requirements dictate that I also need the ability to check equality for only SetA*, SetB*, or SetC*, or combination thereof (SetA* and SetB*, SetA* and SetC*, or SetB* and SetC*) and ignore checking equality for any other Set that is not required in the check.但是要求表明我还需要能够仅检查 SetA*、SetB* 或 SetC* 或它们的组合(SetA* 和 SetB*、SetA* 和 SetC*,或 SetB* 和 SetC*)的相等性并忽略检查检查中不需要的任何其他 Set 的相等性。

Currently, I'm using foreach and LINQ to iterate through the Sets to perform partial equality checks, and that works, but that doesn't seem very efficient for large datasets.目前,我正在使用foreach和 LINQ 来迭代 Sets 以执行部分​​相等性检查,这有效,但对于大型数据集似乎不是很有效。

Maybe the answer is looking at me straight in the face, but I don't see it because I don't have any idea how implement IEquatable that can handle different equality checks.也许答案是直视我的脸,但我没有看到它,因为我不知道如何实现可以处理不同相等性检查的IEquatable

Would someone assist me with some suggestions or directions as to how this may be implemented?有人会就如何实施这一点提供一些建议或指导吗? An example would be even more appreciated.一个例子会更受欢迎。

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

* Update: * * 更新: *

Thanks to Matthew Watson who pointed me in the right direction.感谢 Matthew Watson,他为我指明了正确的方向。 So I implemented a custom comparer as follows.所以我实现了一个自定义比较器,如下所示。 It looks like it is working, but if anyone sees potential problems or room for better implementation, please feel free to comment.看起来它正在工作,但如果有人看到潜在的问题或更好的实施空间,请随时发表评论。

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

As per Matthew Watson's comment, this is a perfect time to use IEqualityComparer<T> rather than IEquatable<T> .根据 Matthew Watson 的评论,这是使用IEqualityComparer<T>而不是IEquatable<T>的最佳时机。 I would suggest only implementing IEquatable<T> when there's a single obvious, natural definition of equality for a type.我建议只在类型的相等性有一个明显的、自然的定义时才实现IEquatable<T> When there are multiple options for equality and no single option is more reasonable than the others, implement IEqualityComparer<T> - either in several different implementation types, or in a single implementation type that is parameterized in terms of creation.当有多个相等选项并且没有一个选项比其他选项更合理时,实现IEqualityComparer<T> - 在几种不同的实现类型中,或者在根据创建参数化的单个实现类型中。

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

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