我有一个看似常见的问题/模式。同一个对象的两个集合。该对象具有许多属性和一些嵌套对象。 Car有一个名为id的属性,它是唯一的标识符。
我想找到LINQ方式来做一个diff,其中包括:
答案 0 :(得分:10)
您可以使用Enumerable.Except()
方法。这使用比较器(默认值或您提供的比较器)来评估两个序列中的对象或只有一个:
var sequenceA = new[] { "a", "e", "i", "o", "u" };
var sequenceB = new[] { "a", "b", "c" };
var sequenceDiff = sequenceA.Except( sequenceB );
如果要完成两个序列(A-B) union (B-A)
的完全分离,则必须使用:
var sequenceDiff =
sequenceA.Except( sequenceB ).Union( sequenceB.Except( sequenceA ) );
如果您有复杂类型,可以为类型T编写IComparer<T>
并使用接受比较器的重载。
对于问题的第二部分,您需要滚动自己的实现来报告类型的哪些属性不同。直接在.NET BCL中没有内置任何内容。您必须决定此报告采用何种形式?您如何识别和表达复杂类型的差异?你当然可以使用反射...但如果你只处理一种类型我会避免这种情况,并为它编写一个专门的差异实用程序。如果你要支持borad范围的类型,那么反思可能更有意义。
答案 1 :(得分:2)
你的上半场已经收到了很好的答案。正如LBushkin解释的那样,下半场不能直接由BCL课程完成。这是一个简单的方法,遍历所有公共可设置的属性(注意:在这些情况下,gettor可能不公开!)并逐个比较它们。如果两个对象100%相等,则返回true。否则,它会提前爆发并返回错误:
static bool AllSettablePropertiesEqual<T>(T obj1, T obj2)
{
PropertyInfo[] info1 = obj1.GetType().GetProperties(
BindingFlags.Public |
BindingFlags.SetProperty |
BindingFlags.Instance); // get public properties
PropertyInfo[] info2 = obj2.GetType().GetProperties(
BindingFlags.Public |
BindingFlags.SetProperty |
BindingFlags.Instance); // get public properties
// a loop is easier than linq here, and we can break out quick:
for (var i = 0; i < info1.Length; i++)
{
var value1 = info1[i].GetValue(obj1, null);
var value2 = info2[i].GetValue(obj2, null)
if(value1 == null || value2 ==null)
{
if(value1 != value2)
return false;
}
else if (!value1.Equals(value2))
{
return false;
}
}
return true;
}
您可以轻松地将此方法添加到标准LINQ表达式中,如下所示:
var reallyReallyEqual = from itemA in listA
join itemB in listB
on AllSettablePropertiesEqual(itemA, itemB)
select itemA;