将对象集合与 ContainsExactly 进行比较

Comparing Collection of Objects with ContainsExactly

我正在尝试比较在各自集合中具有完全相同对象的两个对象集合。我为 ContainsExactly 编写了一个扩展方法来执行此操作。

但是,我 运行 遇到了一个问题,它说这些集合并不相同,尽管它们是相同的。下面是测试代码:

public static bool ContainsExactly<T>(this List<T> set1, List<T> set2)
    {
        if (set1.Count != set2.Count)
            return false;

        //var isEqual = new HashSet<T>(set1).SetEquals(set2); original test just returned isEqual
        var result = set1.Except(set2);            

        return !result.Any(); //still yields both collections in result


    }

那么我有我的对象:

public class ReferenceClassObjectTest : IEquatable<ReferenceClassObjectTest>
    {
        public int Id { get; set; }
        public TestObject TestObject { get; set; }


        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;

            return Equals((ReferenceClassObjectTest)obj);
        }

        public bool Equals(ReferenceClassObjectTest other)
        {
            var casted = other as ReferenceClassObjectTest;

            if (casted == null)
                return false;

            return Id == casted.Id && TestObject == casted.TestObject;
        }

        public override int GetHashCode()
        {
            var hash = Id;                   

            if(TestObject != null)
            {
                hash = (hash * 397) ^ TestObject.GetHashCode();
            }
            else
            {
                hash = (hash * 397);
            }

            return hash;

        }
    }

public class TestObject : IEquatable<TestObject>
    {
        public int Id { get; set; }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;

            return Equals((TestObject)obj);
        }

        public bool Equals(TestObject other)
        {
            var casted = other as TestObject;

            if (casted == null)
                return false;

            return Id == casted.Id;
        }

        public override int GetHashCode()
        {
            var hashCode = Id;
            hashCode = (hashCode * 397);
            return hashCode;
        }
    }

当我 运行 我的测试时,它们仍然 return 错误:

var set2 = new List<ReferenceClassObjectTest>()
        {
            new ReferenceClassObjectTest
            {
                Id = 1,
                TestObject = new TestObject
                {
                    Id = 2
                }
            },
            new ReferenceClassObjectTest
            {
                Id = 2,
                TestObject = new TestObject
                {
                    Id = 3
                }
            },

        };
        var set3 = new List<ReferenceClassObjectTest>()
        {
            new ReferenceClassObjectTest
            {
                Id = 1,
                TestObject = new TestObject
                {
                    Id = 2
                }
            },
            new ReferenceClassObjectTest
            {
                Id = 2,
                TestObject = new TestObject
                {
                    Id = 3
                }
            },

        };

Assert.IsTrue(set2.ContainsExactly(set3));

关于为什么即使在覆盖 GetHashCode() 时它们也不能正确比较的任何见解?

我认为 HashSet.SetEquals() 会考虑我对 GetHashCode() 的覆盖,当我在列表中的两个单独对象上调用 get hashcode 时,我确实得到了相同的哈希:.

set3[1].TestObject.GetHashCode() 1191

set2[1].TestObject.GetHashCode() 1191

set2[0].GetHashCode() 663

set3[0].GetHashCode() 663

您为 ReferenceClassObjectTest 定义的 Equals 使用 == 而不是为 TestObject 调用 Equals,因此您正在比较 TestObjects.

将其更改为:

return Id == other.Id && TestObject.Equals(other.TestObject);

或者,如果您认为 TestObject 是一个不可变对象(因为它有一个 public int 字段,我认为不是),您应该实现 operator== 来调用 Equals .