比较同一对象的版本

时间:2011-07-13 19:05:15

标签: c#

比较同一对象的两个版本并返回差异列表(属性名称,旧值和新值)的最佳方法是什么。有关示例,请参阅下面的对象图。如果产品名称发生变化怎么办,我怎么把它搞砸到属性差异列表中呢?

     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; }
    }
}

4 个答案:

答案 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

但这样做非常脆弱。例如,如果您有任何类型的循环关系,它很容易导致堆栈溢出。 (例如,DateTimeDate属性的形式执行,因此我必须将其包含在基本类型中。)如果您有一些依赖于其他属性的属性,则可能存在一个实际差异多次报告。 (如果DateTime不是循环的,那么会发生这种情况:DateTimes属性中有两个Seconds不同的TotalSecondsTotalMinutes等。 )

答案 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)。

如果您正在考虑创建可重用的组件,则应考虑使用反射类。使用反射,您可以查看所有属性值,即使您不知道所有属性名称。