2012-01-18 77 views
1

我正在爲審計日誌記錄(誰更改什麼成員,何時)進行「深度比較」。我正在使用反射,遞歸到結構中並進行比較。儘管包含字典的人遇到了問題。「深度比較」字典

我可以通過typeof(IDictionary).IsAssignableFrom(memberType)檢測到成員是字典。然後,我的計劃是收集這兩個對象中存在的密鑰,並繼續對這些對象進行遞歸。但是,IDictionary.Keys是一個ICollection,它不被LINQ擴展。不知道鑰匙的類型,我怎麼能做到這一點?

也許這種方法不是最佳的(我不是那種在泛型/反射組合中經驗豐富的),我應該以另一種方式做到這一點嗎?

+0

你的問題與LINQ有什麼關係? – Seb 2012-01-18 15:19:13

+0

@DavidM:只有模板版本,不是'IEnumerable'。在我的問題中說'memberType'將會是'Dictionary '。這是可以分配給'IDictionary',但據我所知,不可能做'IDictionary ',所以我卡住了與非泛型的'IDictionary'。 – carlpett 2012-01-19 08:22:14

回答

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 

您可以創建一個幫助器方法,首先測試type是否爲泛型,然後檢查泛型參數類型。這將不僅測試通用字典,而且測試任何具有通用參數的類型。 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); 
}