按特定值比较子列表与父列表

Compare list of child to list of parent by specific value

我有 2 个列表,第一个是父对象,第二个是子对象。子对象有额外的 属性,我想将其与父对象 class 的 属性 进行比较。

这是例子

  public class Parent
{
    public int X { get; set; }
}

public class Child : Parent
{
    public int Y { get; set; }
}

public class ClassXCompare : IEqualityComparer<Parent>
{
    public bool Equals(Parent x, Parent y)
    {
        var child = (Child)y;
        return x.X == child.Y;
    }

    public int GetHashCode(Parent parent)
    {
        int parentXhash = parent.X.GetHashCode();
        // Calculate the hash code for the product. 
        return parentXhash ;
    }
}

现在如果我测试以下内容,它总是失败

var parentList= new List<Parent>
        {
            new Parent {X = 5},
            new Parent {X = 6}
        };
        var childList= new List<Child>
        {
            new Child {Y = 5},
            new Child {Y = 6}
        };
        var compare = new ClassXCompare();
        var diff = parentList.Except(childList, compare);
        Assert.IsTrue(!diff.Any()); // Fail ???

我认为我的问题出在 GetHashCode 函数

知道如何解决这个问题吗?

(Please ignore the design of the application this is simplified version of the issue)

仅当 GetHashCode returns 两个项目的值相同时才会调用 Set/Dictionary 中的等于 - 参见 General advice and guidelines on how to properly override object.GetHashCode()。修复它的最简单方法是使用类似这样的方法,其中 child 值用于计算 HashCode(如果可用):

public class ClassXCompare : IEqualityComparer<Parent>
{
    public bool Equals(Parent x, Parent y)
    {
        var child = (Child)y;
        return x.X == child.Y;
    }

    public int GetHashCode(Parent parent)
    {
        var child = parent as Child;
        return child == null ?
            parent.X : child.Y.
    }
}

虽然如果你必须处理多个 child 类.

不确定是否有一种简单的方法来处理多个 child 类,除了一些自定义 generic IEqualityComparer,即使那样也只会缩短一点。

P.S. 另外我不确定第二个参数是否总是 Child (怀疑标准涵盖了它,尽管当前在这种特殊用法似乎以适当的方式工作),因此您可能必须 IEqualityComparer 对参数的顺序更加宽松。

这真是糟糕的设计。在比较器中转换为特定类型的需要会给您带来无穷无尽的麻烦。

但是,下面的代码通过了。请注意不同的转换方法、null 检查和 except 行上列表的顺序。

问题是 Child 实例没有设置 X 并且 Except 方法将值传递给 Equals 的顺序意味着 "x" 是 Child 而不是 "y"。

这可能 "work" 但您应该认真地重新考虑您的设计。

public class Parent
{
    public int X { get; set; }
}

public class Child : Parent
{
    public int Y { get; set; }
}

public class ClassXCompare : IEqualityComparer<Parent>
{
    public bool Equals(Parent x, Parent y)
    {
        var child = y as Child;

        return child != null && x.X == child.Y;
    }

    public int GetHashCode(Parent parent)
    {
        var c = parent as Child;
        if (c == null)
            return parent.X.GetHashCode();
        else
            return c.Y.GetHashCode();
    }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var parentList = new List<Parent>
            {
                    new Parent {X = 5},
                    new Parent {X = 6}
            };
        var childList = new List<Child>
            {
                    new Child {Y = 5},
                    new Child {Y = 6}
            };
        var compare = new ClassXCompare();
        var diff = childList.Except(parentList, compare);
        Assert.IsTrue(!diff.Any()); // Fail ???     
    }
}