【问题标题】:"Deep compare" dictionaries“深度比较”词典
【发布时间】:2012-02-13 06:35:24
【问题描述】:

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

我可以通过typeof(IDictionary).IsAssignableFrom(memberType) 检测到一个成员是字典。然后我的计划是收集两个对象中都存在的键,并继续对它们进行递归。但是,IDictionary.Keys 是一个ICollection,它没有被 LINQ 扩展。不知道键的类型,我怎么能做到这一点?

也许这种方法不是最理想的(我在泛型/反射组合方面没有那么丰富的经验),我应该用其他方法吗?

【问题讨论】:

  • 您的问题与 LINQ 有什么关系?
  • @DavidM:只有模板版本,不是IEnumerable。在我的问题中说memberType 将是Dictionary<string, int>。这可以分配给IDictionary,但据我所知,不可能做到IDictionary<memberType.GetGenericParameters()[0], memberType.GetGenericParameters()[1]>,所以我坚持使用非通用IDictionary

标签: c# reflection audit audit-logging


【解决方案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);
}

【讨论】:

    【解决方案2】:

    自己找到了解决方案。这里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;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 2021-11-11
      • 2012-03-26
      相关资源
      最近更新 更多