2017-08-10 45 views
0

考虑下面的代码:LINQ与多个密钥字典的单个值

public KeyAttribute : Attribute{ 
    public string Value; 
    public KeyAttribute(string value){ 
     Value = value; 
    } 
} 

[Key("A")] 
[Key("AB")] 
public class A : IClass 
{ 
    public string FieldA {get;set;} 
} 

[Key("B")] 
public class B : IClass 
{ 
    public string FieldB {get;set;} 
} 

所以我要通过IClass接口的所有的实现,我一定要建立一个字典Dictionary<string, ConstructorInfo>其中键是KeyAttributeValue属性,并且值是相应的ConstructorInfo
请注意,单个类上可能有几个KeyAttribute,因此在这种情况下,字典中应该有相应数量的条目。

对于当前的例子,理想的结果是:

key  | value 
--------+------------------- 
"A"  | ConstructorInfo A 
"AB" | ConstructorInfo A 
"B"  | ConstructorInfo B 

起初,我写了这个:

return AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(s => s.GetTypes()) 
    .Where(t => typeof(IClass).IsAssignableFrom(t)) 
    .ToDictionary(t => 
    { 
     var key = (KeyAttribute) t.GetCustomAttributes(typeof(KeyAttribute), true).First(); 
     return key.Value; 
    }, t => t.GetConstructors(BindingFlags.Public).First()); 

但正如你所看到的,上面的代码不处理与几个情况属性。 所以我做了以下,但它显然是错误的,我不知道如何纠正它。

​​

我知道我可以做,没有LINQ这样的:

var types = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(s => s.GetTypes()) 
    .Where(t => typeof(IClass).IsAssignableFrom(t)); 
var dict = new Dictionary<string, ConstructorInfo>(); 
foreach (var type in types) 
{ 
    var keys = type.GetCustomAttributes(typeof(KeyAttribute), true).Cast<KeyAttribute>().Select(a => a.Value); 
    var ctorInfo = type.GetConstructors(BindingFlags.Public).First(); 
    foreach (var key in keys) 
    { 
     dict.Add(key, ctorInfo); 
    } 
} 
return dict; 

但我宁愿坚持LINQ,如果可能的话。

对于所有这些有关属性和所有这些有点误导性的细节,抱歉,虽然这是一个关于LINQ的问题,但我想不出任何其他生动的例子。

回答

3

这应该工作:

return AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(s => s.GetTypes()) 
    .Where(t => typeof(IClass).IsAssignableFrom(t)) 
    .SelectMany(t => t.GetCustomAttributes(typeof(KeyAttribute), true) 
     .Select(a => new 
     { 
      constInfo = t.GetConstructors(BindingFlags.Public).First(), 
      attrVal = ((KeyAttribute)a).Value 
     })) 
    .ToDictionary(entry => entry.attrVal, entry => entry.constInfo); 
+0

嘿,感谢的答案!答案有点小问题 - 第一个“Select”实际上应该是“SelectMany”。否则,我们必须处理'IEnumerable '而不是'IEnumerable '。 –

+0

@DmitryVolkov好点 –

1

使用SelectMany的关键属性

return AppDomain.CurrentDomain.GetAssemblies() 
       .SelectMany(s => s.GetTypes()) 
       .Where(t => typeof(IClass).IsAssignableFrom(t)) 
       .SelectMany(t => 
       { 
        return t.GetCustomAttributes<KeyAttribute>() 
          .Select(ka => new 
          { 
           Key = ka, 
           Ctor = t.GetConstructors(BindingFlags.Public).First() 
          }); 
       }) 
       .ToDictionary(t => t.Key, t.Ctor); 
相关问题