创建从属性名称到具有该属性的类型的映射

时间:2014-04-04 14:19:06

标签: c# linq reflection

如果有一个简洁/ LINQy的方式来填充这个字典,我只花了大约20分钟试图找出工作:

private Dictionary<string, List<Type>> _propertyMap;

它的目的是成为一个字典,它从有限的类型列表中将公共属性的名称映射到具有此类属性的类型。

我确信必须有一种聪明的方法来获取类型列表,将其扩展为成对的{Type, PropertyInfo}并从那里构建这个字典,但我无法理解它。

这是我填充此词典的当前方式。 (_typesList<Type>):

_propertyMap = new Dictionary<string, List<Type>>();
foreach (var t in _types)
{
    foreach (var p in t.GetProperties(
             System.Reflection.BindingFlags.Public |
             System.Reflection.BindingFlags.Instance))
    {
        if (_propertyMap.ContainsKey(p.Name))
        {
            _propertyMap[p.Name].Add(t);
        }
        else
        {
            _propertyMap[p.Name] = new List<Type> {t};
        }
    }
}

2 个答案:

答案 0 :(得分:4)

您可以使用LINQ查询:

var flags = BindingFlags.Public | BindingFlags.Instance;

_propertyMap = _types.SelectMany(t => t.GetProperties(flags))
                     .GroupBy(p => p.Name)
                     .ToDictionary(g => g.Key, 
                                   g => g.Select(p => p.DeclaringType).ToList());

旁注 - 您可以使用ILookup<string, Type>代替Dictionary<string, List<Type>>,然后查询会这样:

_propertyMap = _types.SelectMany(t => t.GetProperties(flags))
                     .ToLookup(p => p.Name, p => p.DeclaringType);

答案 1 :(得分:0)

我对Sergey's answer感到非常满意,并会继续将其视为已接受。

然而,在我的特殊情况下,当我有两种类型,其中一种从另一种继承时,我后来遇到了麻烦。在这种情况下,DeclaringType返回基类和派生类的基类。

所以我对它的调整,更接近我最初推测的方法,是:

types.SelectMany(t => t
         .GetProperties(BindingFlags.Public | BindingFlags.Instance)
         .Select(p=>new{t,p}))
.GroupBy(p => p.p.Name)
.ToDictionary(g => g.Key, g => g.Select(p => p.t).ToList());