2014-12-10 4 views
0

Я пытаюсь получить все поля, которые были изменены, сравнивая два объекта одного типа.Сравнение двух объектов одного типа

Например:

public class Order 
{ 
    public int OrderNumber {get;set;} 
    public DateTime OrderDate {get;set}; 
    public string Something {get;set}; 
} 

Затем я сохраняю новый заказ:

Order order1 = new Order; 
order1.OrderNumber = 1; 
order1.OrderDate = DateTime.Now; 
order1.Something = string.Empty; 

Save(order1) 

После этого, кто-то пытается изменить некоторую информацию из этого порядка, и я пытаюсь выяснить, лучший способ получить все поля, которые были изменены и сохранены в журнале.

Это должно работать для любого типа двух объектов;

Должен быть способ, как

public something ReturnFields(TObject objectSaved, TObject objectChanged) 

Может кто-нибудь мне помочь?

+2

Вы знали, что Entity Framework делает это за вас? –

+0

Есть ли проблемы с написанием 3 Если утверждения? – Neolisk

+1

«должен работать для любого типа двух объектов» - :) как бы вы определяли равенство для одного объекта с однократным прочтением, например, как «NetworkStream»? Равенство - сложнейшая тема, чем выглядит ... –

ответ

0

Вы можете использовать отражение, чтобы получить свойства объекта, и построить серию выражений для сравнения каждого свойства. Таким образом вы можете выполнить их, а для тех, которые не равны, вернуть их имена вызывающему.

Это потребует расширения, хотя если сами типы свойств не являются всеми типами значений, как в вашем примере, в противном случае это будет делать только проверку ссылочного равенства.

public static class PropertyCompare<T> 
{ 
    public readonly static Func<T, T, List<string>> ChangedProps; 

    private class PropertyComparer<T> 
    { 
     public Func<T, T, bool> Compare { get; set; } 
     public string PropertyName { get; set; } 
    } 

    static PropertyCompare() 
    { 
     PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public); 
     var firstObject = Expression.Parameter(typeof(T), "a"); 
     var secondObject = Expression.Parameter(typeof(T), "b"); 
     PropertyComparer<T>[] propertyComparers = new PropertyComparer<T>[properties.Length]; 

     for (int i = 0; i < properties.Length; i++) 
     {       
      PropertyInfo thisProperty = properties[i]; 
      Expression arePropertiesEqual = Expression.Equal(Expression.Property(firstObject, thisProperty), Expression.Property(secondObject, thisProperty)); 
      Expression<Func<T, T, bool>> equalityFunc = Expression.Lambda<Func<T, T, bool>>(arePropertiesEqual, firstObject, secondObject); 

      PropertyComparer<T> comparer = new PropertyComparer<T>() 
      { 
       Compare = equalityFunc.Compile(), 
       PropertyName = properties[i].Name 
      }; 

      propertyComparers[i] = comparer;       
     } 

     ChangedProps = new Func<T,T,List<string>>((a,b) => 
     { 
      List<string> changedFields = new List<string>(); 

      foreach (PropertyComparer<T> comparer in propertyComparers) 
      { 
       if (comparer.Compare(a, b)) 
        continue; 
       changedFields.Add(comparer.PropertyName); 
      } 

      return changedFields; 
     }); 
    } 
}  

public class Order 
{ 
    public int OrderNumber {get;set;} 
    public DateTime OrderDate {get;set; } 
    public string Something {get; set; } 
} 

static void Main(string[] args) 
{ 
    Order myOrder1 = new Order() { OrderDate = DateTime.Today, OrderNumber = 1, Something = "bleh" }; 
    Order myOrder2 = new Order() { OrderDate = DateTime.Today.AddDays(1), OrderNumber = 1, Something = "bleh" }; 
    List<string> changedFields = PropertyCompare<Order>.ChangedProps(myOrder1, myOrder2); 

    Console.ReadKey(); 
} 
+0

Спасибо! Я создал проект, и он работает отлично. Я попытаюсь использовать вашу идею в своем проекте. Большое спасибо! –

0

Если вы используете журнал, как TXT вы можете сделать ваше возвращение функции это строка, как этот ниже:

public string ReturnFields(TObject objectSaved, TObject objectChanged) 
{ 

    var sb = new StringBuilder(); 

    if(!objectSaved.Name.Equals(objectChanged.Name) 
    { 

    sb.Append("Name was changed from " + objectSaved.Name +" to: " + objectChanged.Name) 

    } 

    if(!objectSaved.OrderDate.Equals(objectChanged.OrderDate) 
    { 

    sb.Append("The date whas changed from " + objectSaved.OrderDate+" to: " + objectChanged.OrderDate) 

    } 

    return sb.ToString(); 
} 

Это просто простой способ, вы можете прочитать немного о Linq выражений, чтобы сделать это к.

+0

Он работает, если объекты всегда будут «Заказать». Но я думал о чем-то для общих объектов из моей программы. –

Смежные вопросы