我有一个有很多属性的类。浅拷贝足以完全复制对象。
我需要比较一个对象,以检查它是否包含与另一个对象完全相同的值。
我的想法:
第一个也是最明显的解决方案就是创建一个巨大的方法块,逐个比较每个属性。
第二种方法是序列化每个对象并对文件进行散列或对其执行某种md5校验和。 (这实际上是否有效)。
第三个是对对象进行某种反思,这会自动化第一个选项,但会增加复杂程度。
速度确实不是问题。
有兴趣听到思考,或者我缺少任何其他方法来做这样的事情。
编辑: 谢谢大家。我的解决方案:(现在修改为通用项目的递归)。
public static bool IsSame<T>(T objA, T objB)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var pi in properties.Where(a => a.CanRead))
{
if (pi.Name == "Item")
{
var piCount = properties.FirstOrDefault(a => a.Name == "Count");
int count = -1;
if (piCount != null && piCount.PropertyType == typeof(System.Int32))
count = (int)piCount.GetValue(objA, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
dynamic child1 = pi.GetValue(objA, new object[] { i });
dynamic child2 = pi.GetValue(objB, new object[] { i });
return IsSame(child1, child2);
}
}
}
else
{
var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
return false;
}
}
return true;
}
答案 0 :(得分:6)
大多数序列化程序旨在确保数据在序列化和反序列化期间保持其完整性,而不是生成一致的序列化格式。我会避免为此目的使用序列化。
您可以考虑实施IEquatable,让每个实例都能够将自己与同一类型的实例进行比较。或者一个班级为您实现IEqualityComparer的比较。他们如何做这种比较可能是一个接一个地比较属性或使用反射的“大方法”。
反射可以是实现目标的一种相当快速和简单的方法,但可能导致问题(例如,如果有人在您的类型中添加了一个不应包含在内的属性来比较相等性),但显然反过来也是如此true(有人添加了应检查相等性的属性,但不更新相等性比较)。您使用哪种方法通常应取决于团队对每种方法的适应程度,以及使用该类的上下文。
在您的情况下,我可能建议使用基于反射的方法,因为您希望检查浅克隆操作的结果,因此所有属性应该相等。
另外,我建议使用MemberwiseClone方法创建克隆,这样可以减少对这种严格测试的需求。
答案 1 :(得分:6)
第三个选项(反射)将是最慢的,但它也是最强大/可测试的。
哈希代码与第一个选项非常相似,因为您必须调用所有成员变量,因此1和2会要求您每次更新.Equals(obj)
和.GenerateHash()
方法修改成员变量列表的时间。
这里有一些代码可以帮助您入门:
foreach (FieldInfo field in this.GetType().GetFields())
{
if (o[field.Name] == null)
{
if (!field.GetValue(this).Equals(o[field.Name]))
return false;
}
else
{
return false;
}
}
return true;
答案 2 :(得分:1)
另一个想法是,如果属性返回简单值类型,您可以将它们分组为自己的不可变值类型。例如,如果您的客户的属性为string Address1
string Address2
string City
string State
string Zip
,则可以创建一个值类型Address,用于实现自己的相等比较器和用那个。
不确定这是否适用于您的情况,但我发现当我有一个具有大量属性的类时,通常可以这样做,并且它往往使我的类更简单,更容易推理
答案 3 :(得分:1)
如果序列化,则必须在每个Field / Property上指定序列化顺序,以确保所有数据按相同顺序序列化。但你要做的就是在外部类中实现GetHashCode()。
GetHashCode()有一些关于如何覆盖它的示例,请先查看。
如果您的班级有很多字段,并且您不想手动编写所有代码。您可以使用反射来自动生成代码。如果您的类不时更改,那么您可以在T4模板中使用GetHashCode()实现创建一个分部类。