我正在对审计日志记录的数据结构进行“深度比较”(谁更改了成员,何时更改)。我正在使用反射,递归到结构并比较它们。我遇到了包含字典的问题。
我可以通过typeof(IDictionary).IsAssignableFrom(memberType)
检测到某个成员是字典。我的计划是收集两个对象中存在的键,并继续递归。但是,IDictionary.Keys
是ICollection
,LINQ不会对其进行扩展。不知道键的类型,我怎么能实现这个?
也许这种方法不是最理想的(我在Generics / Reflection组合中没有经验),我应该用另一种方式吗?
答案 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;
}