2

Я пишу приложение магазина Windows, которое получает объект (настраиваемый тип, который я создал) с сервера, позволяет пользователю редактировать объект, а затем отправляет «набор изменений» обратно на сервер. Этот набор изменений - это просто объект того же типа, что и полученный объект, с каждым полем, установленным в null, за исключением полей, редактируемых пользователем. Эти поля затем содержат изменения пользователя следующим образом:Вычислить набор изменений для объекта

 
Original Case: 
    Description: "Cracked exhaust pipe" 
    Status: "Open" 
    Customer: "" 
    Mileage: 10000 

Edited Case: 
    Description: "" 
    Status "Open" 
    Customer: "Example inc." 
    Mileage: 10000 

Case changeset: 
    Description: "" 
    Status: null 
    Customer: "Example inc." 
    Mileage: null 

Когда приложение первое загружает объект с сервера я сделать копию для последующего сравнения. Затем пользователь вносит изменения в один из объектов, и когда пользователь отправляет свои изменения, набор изменений этих двух объектов вычисляется с помощью общего метода CalculateChangeSet. Он проходит через каждое свойство двух объектов и сравнивает их равенства:

public static T CalculateChangeSet<T>(T oldObject, T newObject) where T : new() 
{ 
    T changeSet = (T)Activator.CreateInstance(oldObject.GetType()); 

    foreach (PropertyInfo property in oldObject.GetType().GetRuntimeProperties()) 
    { 
     var oldValue = property.GetValue(oldObject); 
     var newValue = newObject.GetType().GetRuntimeProperty(property.Name).GetValue(newObject); 
     if (oldValue != null && newValue != null) 
     { 
      if (oldValue is IList) 
      { 
       Type listType = oldValue.GetType().GetRuntimeProperty("Item").PropertyType; 

       IList<listType> oldList = (IList<listType>)oldValue; //Visual studio complains about 
       IList<listType> newList = (IList<listType>)newValue; //listType not being found 

       if (!oldList.SequenceEqual(newList)) 
       { 
        changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null); 
       } 
      } 
      else 
      { 
       if (!oldValue.Equals(newValue)) 
       { 
        changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, CalculateChangeSet(oldValue, newValue)); 
       } 
      } 
     } 
     else 
     { 
      changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue); 
     } 
    } 

    return changeSet; 
} 

Метод штрафа для каждого свойства, я сталкивался за исключением списков работает, так что я создал, если условие, чтобы иметь дело со списками. Поскольку list1.Equals(list2) не сравнивает элементы в списках, нам нужно сделать oldValue и newValue до List<T>, чтобы иметь возможность использовать list.SequenceEqual().

Почему я получаю сообщение об ошибке The type or namespace name 'listType' could not be found (are you missing a using directive or an assembly reference?), когда я пытаюсь использовать его для создания новых списков? Если есть лучший способ подойти к этой проблеме я открыт для предложений ..

ответ

0

Попробуйте это:

IList oldList = (IList)oldValue; //Visual studio complains about 
IList newList = (IList)newValue; //listType not being found 

if (!NonGenericSequenceEqual(oldList, newList)) 
{ 
    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null); 
} 

public static bool NonGenericSequenceEqual(IList a, IList b) 
{ 
    if (ReferenceEquals(a, b)) 
    { 
     return true; 
    } 
    else if (a == null || b == null) 
    { 
     return false; 
    } 
    else 
    { 
     int count = a.Count; 

     if (count != b.Count) 
     { 
      return false; 
     } 
     else 
     { 
      for (int i = 0; i < count; i++) 
      { 
       if (!Object.Equals(a[i], b[i])) 
       { 
        return false; 
       } 
      } 

      return true; 
     } 
    } 
} 

Слабый код «Object.Equals (а [я], б [я]) '

Другой вариант с помощью отражения:

if (!(bool)typeof(System.Linq.Enumerable).GetMethod("SequenceEqual").MakeGenericMethod(oldValue.GetType().GetRuntimeProperty("Item").PropertyType).Invoke(null, new object[] { oldObject, newObject })) 
{ 
    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null); 
} 
+0

[ 'SequenceEqual' не принимает необщего' значения IEnumerable'] (http://msdn.microsoft.com/en-gb/library/bb348567 .aspx). – shambulator

+0

И не только это, но класс, реализующий 'IList ', не обязательно реализует 'IList'. Хотя это можно преодолеть, используя 'IEnumerable' вместо' IList'. – shambulator

+0

решение отражения не работает .. GetMethod не существует в структуре хранилища окон, но GetRuntimeMethod делает. Однако GetRuntimeMethod требует наличия массива типов в качестве второго параметра, поэтому он возвращался к исходной проблеме (не имея возможности использовать listType). Я, однако, использовал слегка измененную версию вашего NonGenericSequenceEqual, поэтому спасибо за это – jbb

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