比较同一对象的两个版本并返回差异列表(属性名称,旧值和新值)的最佳方法是什么。有关示例,请参阅下面的对象图。如果产品名称发生变化怎么办,我怎么把它搞砸到属性差异列表中呢?
static void Main(string[] args)
{
Customer c1 = new Customer();
c1.DBA = "Test1";
c1.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c1.LatestOrder.OrderDetails.Product = "Product1";
Customer c2 = new Customer();
c2.DBA = "Test1";
c2.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c2.LatestOrder.OrderDetails.Product = "Product2";
}
因此上面的测试显示,除产品名称外,2个对象中的所有内容都相同。也许,就像概念证明一样,列表显示属性名称,旧值和新值。
public class Customer
{
public string DBA { get; set; }
public Order LatestOrder { get; set; }
public Customer()
{
LatestOrder = new Order();
}
}
public class Order
{
public int Id { get; set; }
public DateTime DateOrdered { get; set; }
public OrderDetails OrderDetails { get; set; }
public Order()
{
OrderDetails = new OrderDetails();
}
}
public class OrderDetails
{
public String Product { get; set; }
}
}
答案 0 :(得分:1)
这可能有助于你开始,基本上如果你知道obj1和obj2属于同一类型,你获得所有的公共属性并逐个进行比较......你可能想要以不同的方式处理集合(比较每个集合中的项目)...
然后你可以在一些字典或自定义对象中编译所有这些信息。
foreach (var info in obj1.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = info.GetValue(obj1, null);
var val2 = info.GetValue(obj2, null);
// check if val1 == val2
}
答案 1 :(得分:1)
你可以用反射来试试。像这样:
class Difference
{
private Difference(string propertyPath, object value1, object value2)
{
PropertyPath = propertyPath;
Value1 = value1;
Value2 = value2;
}
public string PropertyPath { get; private set; }
public object Value1 { get; private set; }
public object Value2 { get; private set; }
public Difference Extend(string propertyName)
{
return new Difference(
string.Format("{0}.{1}", propertyName, PropertyPath), Value1, Value2);
}
public override string ToString()
{
return string.Format("{0}: {1}, {2}", PropertyPath, Value1, Value2);
}
public static IEnumerable<Difference> GetDifferences<T>(T value1, T value2)
{
return GetDifferences(typeof(T), value1, value2);
}
// types in this collection are compared directly
// and not recursively using their properties
private static readonly Type[] PrimitiveTypes =
new[] { typeof(int), typeof(string), typeof(DateTime) };
public static IEnumerable<Difference> GetDifferences(
Type type, object obj1, object obj2)
{
foreach (var property in
type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = property.GetValue(obj1, null);
var val2 = property.GetValue(obj2, null);
if (PrimitiveTypes.Contains(property.PropertyType))
{
if (!val1.Equals(val2))
yield return new Difference(property.Name, val1, val2);
}
else
{
foreach (var difference in
GetDifferences(property.PropertyType, val1, val2))
yield return difference.Extend(property.Name);
}
}
}
}
以递归方式遍历对象图并返回类似
的内容LatestOrder.DateOrdered: 12.7.2011 0:00:00, 11.7.2011 0:00:00
LatestOrder.OrderDetails.Product: Product1, Product2
但这样做非常脆弱。例如,如果您有任何类型的循环关系,它很容易导致堆栈溢出。 (例如,DateTime
以Date
属性的形式执行,因此我必须将其包含在基本类型中。)如果您有一些依赖于其他属性的属性,则可能存在一个实际差异多次报告。 (如果DateTime
不是循环的,那么会发生这种情况:DateTimes
属性中有两个Seconds
不同的TotalSeconds
,TotalMinutes
等。 )
答案 2 :(得分:0)
您可以执行与Comparable类类似的操作,但使用差异列表而不是整数。例如
public class ClassName {
...
ArrayList compareTo(ClassName other) {
if (this.attribute.equals(other.attribute)) {
add to list
}
}
}
答案 3 :(得分:0)
如果旧版本和新版本位于同一对象实例中,您可以使用Memento模式的变体(http://en.wikipedia.org/wiki/Memento_pattern)。
如果您正在考虑创建可重用的组件,则应考虑使用反射类。使用反射,您可以查看所有属性值,即使您不知道所有属性名称。