我有一个比较两个对象的方法,并返回一个不同的所有属性名称的列表。
public static IList<string> GetDifferingProperties(object source, object target)
{
var sourceType = source.GetType();
var sourceProperties = sourceType.GetProperties();
var targetType = target.GetType();
var targetProperties = targetType.GetProperties();
var properties = (from s in sourceProperties
from t in targetProperties
where s.Name == t.Name &&
s.PropertyType == t.PropertyType &&
s.GetValue(source,null) != t.GetValue(target,null)
select s.Name).ToList();
return properties;
}
例如,如果我有两个类如下:
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class Employee
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public Address EmployeeAddress { get; set; }
}
我正在尝试比较以下两个员工实例:
var emp1Address = new Address();
emp1Address.AddressLine1 = "Microsoft Corporation";
emp1Address.AddressLine2 = "One Microsoft Way";
emp1Address.City = "Redmond";
emp1Address.State = "WA";
emp1Address.Zip = "98052-6399";
var emp1 = new Employee();
emp1.FirstName = "Bill";
emp1.LastName = "Gates";
emp1.EmployeeAddress = emp1Address;
var emp2Address = new Address();
emp2Address.AddressLine1 = "Gates Foundation";
emp2Address.AddressLine2 = "One Microsoft Way";
emp2Address.City = "Redmond";
emp2Address.State = "WA";
emp2Address.Zip = "98052-6399";
var emp2 = new Employee();
emp2.FirstName = "Melinda";
emp2.LastName = "Gates";
emp2.EmployeeAddress = emp2Address;
因此,当我将这两个雇员对象传递给我的GetDifferingProperties方法时,它返回FirstName和EmployeeAddress,但它并没有告诉我EmployeeAddress中哪个确切的属性(在本例中是Address1)已经改变了。我如何调整此方法以获得类似EmployeeAddress.Address1?
的内容答案 0 :(得分:3)
这是因为您正在使用!=
,对于对象,它会测试对象的身份而不是其值。关键是使用递归来生成属性的属性列表。这会像你想要的那样深......
public static IList<string> GetDifferingProperties(object source, object target)
{
var sourceType = source.GetType();
var sourceProperties = sourceType.GetProperties();
var targetType = target.GetType();
var targetProperties = targetType.GetProperties();
var result = new List<string>();
foreach (var property in
(from s in sourceProperties
from t in targetProperties
where s.Name == t.Name &&
s.PropertyType == t.PropertyType &&
!Equals(s.GetValue(source, null), t.GetValue(target, null))
select new { Source = s, Target = t }))
{
// it's up to you to decide how primitive is primitive enough
if (IsPrimitive(property.Source.PropertyType))
{
result.Add(property.Source.Name);
}
else
{
foreach (var subProperty in GetDifferingProperties(
property.Source.GetValue(source, null),
property.Target.GetValue(target, null)))
{
result.Add(property.Source.Name + "." + subProperty);
}
}
}
return result;
}
private static bool IsPrimitive(Type type)
{
return type == typeof(string) || type == typeof(int);
}
答案 1 :(得分:2)
我可以推荐使用http://comparenetobjects.codeplex.com/ 这有可能比较嵌套对象,枚举,IList等。 该项目免费且易于使用(仅1 .cs文件)。此外,可以获取不同的值,添加要忽略的属性等。
答案 2 :(得分:1)
原则上,您需要在获取其值后使用GetDifferingProperties
中要实现的两个对象上的技术(在查询中使用GetValue
)。可能最直接的实现是使该方法递归:
public static IEnumerable<string> GetDifferingProperties
(object source, object target) {
// Terminate recursion - equal objects don't have any differing properties
if (source == target) return new List<string>();
// Compare properties of two objects that are not equal
var sourceProperties = source.GetType().GetProperties();
var targetProperties = target.GetType().GetProperties();
return
from s in sourceProperties
from t in targetProperties
where s.Name == t.Name && s.PropertyType == t.PropertyType
let sVal = s.GetValue(source, null)
let tVal = t.GetValue(target, null)
// Instead of comparing the objects directly using '==', we run
// the method recursively. If the two objects are equal, it returns
// empty list immediately, otherwise it generates multiple properties
from name in GetDifferingProperties(sVal, tVal)
select name;
}
如果你想在实践中使用它,你可能想要跟踪如何到达属性(这段代码只给你一个属性名称列表,而没有关于包含它们的对象的信息)。您可以将最后一行从select name
更改为select s.Name + "." + name
,这将为您提供更完整的名称(例如Address.Name
,如果不同的属性是Name
属性Address
1}}成员)。
答案 3 :(得分:0)
一点:您的方法没有考虑EmployeeAddress属性的实际差异。测试一下,看看。
emp2Address.AddressLine1 = emp1Address.AddressLine1;// "Gates Foundation";
emp2Address.AddressLine2 = emp1Address.AddressLine2;// "One Microsoft Way";
emp2Address.City = emp1Address.City;// "Redmond";
emp2Address.State = emp1Address.State;// "WA";
emp2Address.Zip = emp1Address.Zip;// "98052-6399";
程序仍会将EmployeeAddress作为不匹配的属性返回。但是,如果您只是设置emp2.EmployeeAddress = emp1Address,则不会出现“不匹配”。
关于引用的东西......
无论如何,如果您想找到该对象的不同之处,您将不得不搜索以了解该对象的不同之处。