2017-08-10 49 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); 
相關問題