c# 对象与复杂对象的比较
c# Object Comparison With Complex Objects
我有一个通用的对象比较方法,用于比较具有相同结构的两个模型。
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
var variances = new List<Variance>();
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties.Where(t => t.IsMarkedWith<IncludeInComparisonAttribute>()))
{
var v = new Variance
{
PropertyName = property.Name,
ValA = property.GetValue(val1, null),
ValB = property.GetValue(val2, null)
};
if (v.ValA == null && v.ValB == null) { continue; }
if (v.ValA != null && !v.ValA.Equals(v.ValB))
{
variances.Add(v);
}
}
return variances;
}
我遇到的问题是,有时传递给它的对象可能包含其中的其他对象列表。因为它只在顶层比较它只是 returns 对象数组被更改了。理想情况下,我希望它遍历嵌套数组并查看更改后的值。
理想情况下,我认为它应该在找到对象数组时进行递归调用。我有什么想法可以解决这个问题吗?
编辑 - 带有工作示例
这里有一些 .net fiddle 例子说明了它是如何工作的。
这是第一个不向下搜索嵌套对象而仅报告集合已更改的代码示例(按照上面的代码):
https://dotnetfiddle.net/Cng7GI
returns:
属性:NumberOfDesks 已从“5”更改为“4”
属性:学生从'System.Collections.Generic.List1[Student]' to 'System.Collections.Generic.List
1[Student]'
变了
现在,如果我使用以下方法找到嵌套数组,则尝试调用 DetailedCompare:
if (v.ValA is ICollection)
{
Console.WriteLine("I found a nested list");
variances.AddRange(v.ValA.DetailedCompare(v.ValB));
}
else if(v.ValA != null && !v.ValA.Equals(v.ValB)){
variances.Add(v);
}
递归调用似乎不起作用
https://dotnetfiddle.net/Ns1tx5
我刚得到:
我找到了一个嵌套列表
属性:NumberOfDesks 已从“5”更改为“4”
如果我添加:
var list = v.ValA.DetailedCompare<T>(v.ValB);
在 Collection 检查中,我得到一个错误:
对象不包含 'DetailedCompare' 的定义...无法将实例参数类型 'object' 转换为 T
我真正想要的只是所有 属性 名称及其值变化的一个数组。
属性:NumberOfDesks 已从“5”更改为“4”
属性: Id 已从“1”更改为“4”
属性:名字已从 'Cheshire' 更改为 'Door'
等等
递归调用方法是这里的问题。
如果我们调用一个方法 DetailedCompare
递归地传递两个对象作为参数就没问题了——因为我们可以获得它们的属性并进行比较。
然而,当我们调用 DetailedCompare
递归传递两个对象列表时 - 我们不能只获取这些列表的属性 - 但我们需要遍历并获取这些列表的属性并比较它们的值。
恕我直言,最好使用辅助方法来分离逻辑 - 这样当我们找到嵌套列表时 - 我们可以按照我上面描述的那样处理逻辑。
这是我写的扩展class
public static class Extension
{
public static List<Variance> Variances { get; set; }
static Extension()
{
Variances = new List<Variance>();
}
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
var v = new Variance
{
PropertyName = property.Name,
ValA = property.GetValue(val1, null),
ValB = property.GetValue(val2, null)
};
if (v.ValA == null && v.ValB == null)
{
continue;
}
if (v.ValA is ICollection)
{
Console.WriteLine("I found a nested list");
DetailedCompareList(v.ValA,v.ValB);
}
else if (v.ValA != null && !v.ValA.Equals(v.ValB))
{
Variances.Add(v);
}
}
return Variances;
}
private static void DetailedCompareList<T>(T val1, T val2)
{
if (val1 is ICollection collection1 && val2 is ICollection collection2)
{
var coll1 = collection1.Cast<object>().ToList();
var coll2 = collection2.Cast<object>().ToList();
for (int j = 0; j < coll1.Count; j++)
{
Type type = coll1[j].GetType();
PropertyInfo[] propertiesOfCollection1 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] propertiesOfCollection2 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < propertiesOfCollection1.Length; i++)
{
var variance = new Variance
{
PropertyName = propertiesOfCollection1[i].Name,
ValA = propertiesOfCollection1[i].GetValue(coll1[j]),
ValB = propertiesOfCollection2[i].GetValue(coll2[j])
};
if (!variance.ValA.Equals(variance.ValB))
{
Variances.Add(variance);
}
}
}
}
}
}
结果如下:
限制
这种方法受对象定义的限制 - 因此它只能使用 1 级深度。
我有一个通用的对象比较方法,用于比较具有相同结构的两个模型。
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
var variances = new List<Variance>();
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties.Where(t => t.IsMarkedWith<IncludeInComparisonAttribute>()))
{
var v = new Variance
{
PropertyName = property.Name,
ValA = property.GetValue(val1, null),
ValB = property.GetValue(val2, null)
};
if (v.ValA == null && v.ValB == null) { continue; }
if (v.ValA != null && !v.ValA.Equals(v.ValB))
{
variances.Add(v);
}
}
return variances;
}
我遇到的问题是,有时传递给它的对象可能包含其中的其他对象列表。因为它只在顶层比较它只是 returns 对象数组被更改了。理想情况下,我希望它遍历嵌套数组并查看更改后的值。
理想情况下,我认为它应该在找到对象数组时进行递归调用。我有什么想法可以解决这个问题吗?
编辑 - 带有工作示例
这里有一些 .net fiddle 例子说明了它是如何工作的。
这是第一个不向下搜索嵌套对象而仅报告集合已更改的代码示例(按照上面的代码):
https://dotnetfiddle.net/Cng7GI
returns:
属性:NumberOfDesks 已从“5”更改为“4”
属性:学生从'System.Collections.Generic.List1[Student]' to 'System.Collections.Generic.List
1[Student]'
现在,如果我使用以下方法找到嵌套数组,则尝试调用 DetailedCompare:
if (v.ValA is ICollection)
{
Console.WriteLine("I found a nested list");
variances.AddRange(v.ValA.DetailedCompare(v.ValB));
}
else if(v.ValA != null && !v.ValA.Equals(v.ValB)){
variances.Add(v);
}
递归调用似乎不起作用
https://dotnetfiddle.net/Ns1tx5
我刚得到:
我找到了一个嵌套列表 属性:NumberOfDesks 已从“5”更改为“4”
如果我添加:
var list = v.ValA.DetailedCompare<T>(v.ValB);
在 Collection 检查中,我得到一个错误:
对象不包含 'DetailedCompare' 的定义...无法将实例参数类型 'object' 转换为 T
我真正想要的只是所有 属性 名称及其值变化的一个数组。
属性:NumberOfDesks 已从“5”更改为“4”
属性: Id 已从“1”更改为“4”
属性:名字已从 'Cheshire' 更改为 'Door'
等等
递归调用方法是这里的问题。
如果我们调用一个方法 DetailedCompare
递归地传递两个对象作为参数就没问题了——因为我们可以获得它们的属性并进行比较。
然而,当我们调用 DetailedCompare
递归传递两个对象列表时 - 我们不能只获取这些列表的属性 - 但我们需要遍历并获取这些列表的属性并比较它们的值。
恕我直言,最好使用辅助方法来分离逻辑 - 这样当我们找到嵌套列表时 - 我们可以按照我上面描述的那样处理逻辑。
这是我写的扩展class
public static class Extension
{
public static List<Variance> Variances { get; set; }
static Extension()
{
Variances = new List<Variance>();
}
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
var v = new Variance
{
PropertyName = property.Name,
ValA = property.GetValue(val1, null),
ValB = property.GetValue(val2, null)
};
if (v.ValA == null && v.ValB == null)
{
continue;
}
if (v.ValA is ICollection)
{
Console.WriteLine("I found a nested list");
DetailedCompareList(v.ValA,v.ValB);
}
else if (v.ValA != null && !v.ValA.Equals(v.ValB))
{
Variances.Add(v);
}
}
return Variances;
}
private static void DetailedCompareList<T>(T val1, T val2)
{
if (val1 is ICollection collection1 && val2 is ICollection collection2)
{
var coll1 = collection1.Cast<object>().ToList();
var coll2 = collection2.Cast<object>().ToList();
for (int j = 0; j < coll1.Count; j++)
{
Type type = coll1[j].GetType();
PropertyInfo[] propertiesOfCollection1 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] propertiesOfCollection2 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < propertiesOfCollection1.Length; i++)
{
var variance = new Variance
{
PropertyName = propertiesOfCollection1[i].Name,
ValA = propertiesOfCollection1[i].GetValue(coll1[j]),
ValB = propertiesOfCollection2[i].GetValue(coll2[j])
};
if (!variance.ValA.Equals(variance.ValB))
{
Variances.Add(variance);
}
}
}
}
}
}
结果如下:
限制 这种方法受对象定义的限制 - 因此它只能使用 1 级深度。