2012-01-18 4 views
1

감사 로깅 (누가 언제 어떤 멤버를 변경했는지)에 대한 데이터 구조를 "심도 비교"하고 있습니다. 나는 이것을 위해 리플렉션을 사용하여 구조를 반복하고 비교합니다. 나는 사전을 포함하는 사람들과 문제를 쳤다."Deep compare"사전

회원이 사전임을 typeof(IDictionary).IsAssignableFrom(memberType)으로 감지 할 수 있습니다. 내 계획은 두 개체에 존재하는 키를 수집하고 그 개체에 대한 재귀를 계속 수행합니다. 그러나 IDictionary.Keys은 LINQ로 확장되지 않은 ICollection입니다. 열쇠의 종류를 알지 못하면 어떻게 이것을 할 수 있습니까?

아마도이 방법은 차선책입니다 (저는 Generics/Reflection 콤보에 익숙하지 않습니다). 다른 방법으로해야합니까?

+0

LINQ와 어떤 관련이 있습니까? – Seb

+0

@DavidM : 템플릿 버전 만, IEnumerable은 아닙니다. 제 질문에'memberType'은'Dictionary '입니다. 그건'IDictionary'에 할당 할 수 있습니다. 그러나 제가 아는 한, IDictionary '을 할 수 없습니다. 제네릭이 아닌 'IDictionary'. – carlpett

답변

0

해결책을 직접 찾았습니다. 여기서 ChangedProperties은 속성 이름을 포함하는 유형이며 변경 전/후 값입니다.

if (typeof(IDictionary).IsAssignableFrom(propertyType)) 
{ 
    Type keyType = propertyType.GetGenericArguments()[0], 
     valueType = propertyType.GetGenericArguments()[1]; 
    Type hashsetType = typeof(HashSet<>).MakeGenericType(keyType); 
    var hashsetCtor = hashsetType.GetConstructor(new[] { typeof(IEnumerable<>).MakeGenericType(keyType) }); 

    dynamic aDict = a; 
    dynamic bDict = b; 
    dynamic aKeys = hashsetCtor.Invoke(new object[] { aDict.Keys }); 
    dynamic bKeys = hashsetCtor.Invoke(new object[] { bDict.Keys }); 

    List<ChangedProperty> changes = new List<ChangedProperty>(); 
    foreach (var key in Enumerable.Intersect(aKeys, bKeys)) 
    { 
      // Present in both dictionaries. Recurse further 
    } 
    foreach (var key in Enumerable.Except(aKeys, bKeys)) 
    { 
      // Key was removed 
    } 
    foreach (var key in Enumerable.Except(bKeys, aKeys)) 
    { 
      // Key was added 
    } 

    return changes; 
} 
1

반향 반복을 도와줍니다.

IDictionary<int, string> t; 

bool t.GetType().IsGenericType 
Type[] t.GetType().GetGenericArguments() 
// you can do foreach here and see again if type is generic 

유형이 제네릭인지 먼저 테스트 한 다음 보조 인수 유형을 확인하는 도우미 메서드를 만들 수 있습니다. 이것은 일반 사전뿐만 아니라 일반 인수가있는 모든 유형을 테스트합니다. IList, KeyValuePair 등

public static bool IsType(Type inputType, Type targetType) 
{ 
    if (inputType.IsGenericType) 
    { 
     Type[] genericArgs = inputType.GetGenericArguments(); 
     var foundType = false; 
     foreach (var item in genericArgs) 
     { 
      if (IsType(item, targetType)) 
       foundType = true; 
     } 
     return foundType; 
    } 
    return inputType.IsAssignableFrom(targetType); 
}