2

서버에서 개체 (내가 만든 사용자 지정 유형)를받는 Windows 저장소 앱을 작성하고 사용자가 개체를 편집 한 다음 서버에 "changeset"을 다시 제출할 수있게합니다. 이 변경 집합은 단순히 사용자가 편집 한 필드를 제외하고 모든 필드가 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)은 목록의 항목을 비교하지 않으므로 을 사용하려면 oldValuenewValueList<T>으로 전송해야합니다.

새 목록을 만들 때 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 '이다 (B, A [i]를 [I]) '

반사를 통해 또 다른 변형 :

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

['제네릭이 아닌'IEnumerable' 값을 허용하지 않습니다 SequenceEqual'] (http://msdn.microsoft.com/en-gb/library/bb348567 .aspx). – shambulator

+0

그리고 그것뿐만 아니라'IList '을 구현하는 클래스는 반드시 IList를 구현하지는 않습니다. 그것은 'IList'대신에'IEnumerable'을 사용함으로써 극복 될 수 있습니다. – shambulator

+0

반사 솔루션이 작동하지 않습니다 .. GetMethod가 Windows 저장소 프레임 워크에 없지만 GetRuntimeMethod가 존재합니다. 그러나 GetRuntimeMethod는 두 번째 매개 변수로 Types 배열을 필요로하므로 원래 문제 (listType을 사용할 수 없음)로 돌아갔습니다. 그러나 나는 당신의 NonGenericSequenceEqual의 약간 수정 된 버전을 사용하여 끝냈다. 그래서 고마워. – jbb

관련 문제