“深度比较”词典

时间:2012-01-18 14:32:35

标签: c# reflection audit audit-logging

我正在对审计日志记录的数据结构进行“深度比较”(谁更改了成员,何时更改)。我正在使用反射,递归到结构并比较它们。我遇到了包含字典的问题。

我可以通过typeof(IDictionary).IsAssignableFrom(memberType)检测到某个成员是字典。我的计划是收集两个对象中存在的键,并继续递归。但是,IDictionary.KeysICollection,LINQ不会对其进行扩展。不知道键的类型,我怎么能实现这个?

也许这种方法不是最理想的(我在Generics / Reflection组合中没有经验),我应该用另一种方式吗?

2 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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;
}