我有2个列表,首先是父对象的第二个子对象。子对象具有额外的属性,我想与父类的属性进行比较。
这是示例
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 功能
知道如何解决这个问题吗?
(请忽略应用程序的设计,这是简化的 问题的版本)
答案 0 :(得分:2)
这是一个真正可怕的设计。在比较器中转换为特定类型的需要将导致您不会遇到麻烦。
但是,下面的代码通过了。请注意不同的转换方法,空检查以及除外行上的列表顺序。
问题是Child实例没有设置X,并且Except方法将值传递给Equals的顺序意味着“x”是Child而不是“y”。
这可能会起作用,但你应该认真重新考虑你的设计。
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 ???
}
}
答案 1 :(得分:0)
只有当GetHashCode为两个项返回相同的值时,才会调用Set / Dictionary中的Equals - 请参阅General advice and guidelines on how to properly override object.GetHashCode()。修复它的最简单方法是使用类似这样的东西,其中子值用于计算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.
}
}
如果你必须处理多个子类,它不是非常可扩展的。
不确定是否有一种简单的方法来处理多个子类,除了一些自定义generic IEqualityComparer之外,甚至只会缩短它。
PS 此外,我不确定第二个参数是否总是Child
(怀疑该标准涵盖了它,尽管此特定用法中的当前实现似乎以适当的方式工作),所以你可能不得不使IEqualityComparer
对参数的顺序更宽松。