c#对象与复杂对象的比较
我有一个通用的对象比较方法,用于比较具有相同结构的两个模型c#对象与复杂对象的比较,c#,comparison,C#,Comparison,我有一个通用的对象比较方法,用于比较具有相同结构的两个模型 public static List<Variance> DetailedCompare<T>(this T val1, T val2) { var variances = new List<Variance>(); var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instan
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;
}
递归调用似乎不起作用
正如我刚刚得到的:
我找到了一个嵌套列表
属性:NumberOfDesks已从“5”更改为“4”
如果我加上:
var list = v.ValA.DetailedCompare<T>(v.ValB);
var list=v.ValA.DetailedCompare(v.ValB);
在集合检查中,我得到一个错误:
对象不包含“DetailedCompare”的定义。。。无法将实例参数类型“object”转换为T
实际上,我想从中得到的只是一个包含所有属性名及其值更改的数组
属性:NumberOfDesks已从“5”更改为“4”
属性:Id已从“1”更改为“4”
属性:名字已从“柴郡”更改为“门”
etc递归调用方法是这里的问题 如果我们调用一个方法
DetailedCompare
递归地将两个对象作为参数传递,这一切都很好,因为我们可以得到它们的属性并对它们进行比较
然而,当我们递归地调用DetailedCompare
传递两个对象列表时,我们不能只获取这些列表的属性,我们需要遍历并获取这些列表的属性,并比较它们的值
IMHO最好使用helper方法来分离逻辑,这样当我们找到一个嵌套列表时,我们就可以像我上面描述的那样处理逻辑了
这是我写的扩展类
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);
}
}
}
}
}
}
公共静态类扩展
{
公共静态列表变量{get;set;}
静态扩展()
{
差异=新列表();
}
公共静态列表DetailedCompare(此T值1,T值2)
{
var properties=typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach(属性中的var属性)
{
var v=新方差
{
PropertyName=property.Name,
ValA=property.GetValue(val1,null),
ValB=property.GetValue(val2,null)
};
if(v.ValA==null&&v.ValB==null)
{
继续;
}
如果(v.ValA是ICollection)
{
WriteLine(“我发现了一个嵌套列表”);
详细比较列表(v.ValA,v.ValB);
}
else如果(v.ValA!=null&!v.ValA.Equals(v.ValB))
{
差异。添加(v);
}
}
回报差异;
}
私有静态无效详细比较列表(T值1,T值2)
{
if(val1是ICollection collection1&&val2是ICollection collection2)
{
var coll1=collection1.Cast().ToList();
var coll2=collection2.Cast().ToList();
对于(int j=0;j
结果如下:
限制
这种方法受对象定义的限制,因此只能在1级深度下使用。挑战在于为嵌套对象存储这些差异。因为他们会在。。或者你想让一个变量包含所有级别的方差吗?我想你不想这样做,不如把顶层的方差设置成字典,其他底层的变量用它们的键存储。。。e、 g
dictionary[“level1”]或dictionary[“level2”]
等。。。您会感激吗?您必须小心引用类型(字符串除外)的相等性比较,这样可能会得到不想要的结果。可能您正在覆盖所有自定义类的相等,否则具有相同值的两个不同实例将不相等。谢谢。我很高兴单变量数组中的所有差异你已经回答了你的问题,你需要递归。如果(ValA是IEnumerable eA&&ValB是IEnumerable eB)并执行一些自定义逻辑,在其中迭代并调用DetailCompare
。然后,您只需要为DetailCompare
创建一个重载,该重载采用类型,而不是
太好了,谢谢。看起来它能完成任务。在我的代码中,v.Valb作为哈希集出现。你知道我该怎么处理吗?if中的casting DetailedCompareList在itI上不起作用,我更改了代码以检查它是否为IEnumerable且是否起作用。谢谢你的帮助。if(val1是IEnumerable collection1&&val2是IEnumerable collection2)
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);
}
}
}
}
}
}