2010-05-24 78 views
3

給定一個特定的接口ITarget<T>和特定類型myType,如果myType執行ITarget<T>,您將如何確定T。 (此代碼段被從答案帶到an earlier question。)如何在字典中實現某個通用接口的所有類型?

foreach (var i in myType.GetInterfaces()) 
    if (i.IsGenericType 
     && i.GetGenericTypeDefinition() == typeof(ITarget<>)) 
     return i.GetGenericArguments()[0] ; 

然而,這僅檢查一個類型,myType。我將如何創建一個字典所有這樣的類型參數,其中的關鍵是T和值是myType?我認爲它看起來像這樣:

var searchTarget = typeof(ITarget<>); 
var dict = Assembly.GetExecutingAssembly().[???] 
      .Where(t => t.IsGenericType 
        && t.GetGenericTypeDefinition() == searchTarget) 
      .[???]; 

空白是什麼?

回答

6
var searchTarget = typeof(ITarget<>); 

var dict = Assembly.GetExecutingAssembly() 
    .GetTypes() 
    .SelectMany(t => t.GetInterfaces() 
         .Where(i => i.IsGenericType 
          && (i.GetGenericTypeDefinition() == searchTarget) 
          && !i.ContainsGenericParameters), 
       (t, i) => new { Key = i.GetGenericArguments()[0], Value = t }) 
    .ToDictionary(x => x.Key, x => x.Value); 

請注意,如果您有多個類實現ITarget<>,並使用相同的通用類型參數 - 例如,class Foo : ITarget<string>class Bar : ITarget<string> - 然後ToDictionary調用將失敗與ArgumentException抱怨,你不能添加同一把鑰匙兩次。

如果您確實需要一對多映射,那麼您有幾個選項可用。

  1. 使用ToLookup而不是ToDictionary生成一個Lookup<K,V>

    var dict = Assembly.GetExecutingAssembly() 
        .GetTypes() 
        .SelectMany(/* ... */) 
        .ToLookup(x => x.Key, x => x.Value); 
    
  2. 如果你喜歡的東西,如一個Dictionary<K,List<V>>工作,那麼你可以這樣做:

    var dict = Assembly.GetExecutingAssembly() 
        .GetTypes() 
        .SelectMany(/* ... */) 
        .GroupBy(x => x.Key, x => x.Value) 
        .ToDictionary(g => g.Key, g => g.ToList()); 
    
+2

備用:'AppDomain.CurrentDomain.GetAssemblies()。Selec tMany(x => x.GetTypes())。 // etc' – Will 2010-05-24 12:27:24

+0

工作完美!非常感謝。但有一個問題:添加'!i.ContainsGenericParameters'的動機是什麼? – 2010-05-24 12:28:29

+0

'!i.ContainsGenericParameters'不包括'C類:ITarget {...}'。 – 2010-05-24 12:33:09

相關問題