2010-05-24 32 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

相关问题