【问题标题】:Comparing Collection of Objects with ContainsExactly将对象集合与 ContainsExactly 进行比较
【发布时间】:2018-06-22 07:03:04
【问题描述】:

我正在尝试比较两个对象集合,它们在各自的集合中具有完全相同的对象。为此,我为 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;
        }
    }

当我运行测试时,它们仍然返回 false:

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

【问题讨论】:

  • 我就坐在你旁边,但我不会亲自帮助你,而是在这里回答。 #introvertpowers
  • 我不知道你是谁?!
  • 为什么在你的Equals 实现中使用castedas?我不相信other 可能不是正确的类型...

标签: c# .net contains iequatable


【解决方案1】:

您对ReferenceClassObjectTestEquals 定义使用== 而不是为Equals 调用TestObject,因此您正在比较TestObjects 的引用标识。

改为:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 2012-01-21
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    相关资源
    最近更新 更多