【问题标题】:How do I put all types implementing a certain generic interface in a dictionary?如何将实现某个通用接口的所有类型放入字典中?
【发布时间】:2011-02-23 05:19:54
【问题描述】:

给定一个特定的接口ITarget<T> 和一个特定的类型myType,如果myType 实现ITarget<T>,您将如何确定T。 (这段代码sn-p取自an earlier question的答案。)

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

但是,这只检查单个类型,myType。我将如何创建 all 此类类型参数的 dictionary,其中键是 T,值是 myType?我认为它看起来像这样:

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

空白处是什么?

【问题讨论】:

    标签: c# generics reflection


    【解决方案1】:
    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&lt;&gt; 的类并使用相同的泛型类型参数(例如,class Foo : ITarget&lt;string&gt;class Bar : ITarget&lt;string&gt;),那么 ToDictionary 调用将失败并出现 ArgumentException 抱怨您不能两次添加相同的密钥。

    如果您确实需要一对多映射,那么您有几个可用的选项。

    1. 使用ToLookup 而不是ToDictionary 来生成Lookup&lt;K,V&gt;

      var dict = Assembly.GetExecutingAssembly()
          .GetTypes()
          .SelectMany(/* ... */)
          .ToLookup(x => x.Key, x => x.Value);
      
    2. 如果您更喜欢使用Dictionary&lt;K,List&lt;V&gt;&gt; 之类的东西,那么您可以这样做:

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

    【讨论】:

    • 备用:AppDomain.CurrentDomain.GetAssemblies().SelectMany(x =&gt; x.GetTypes(). //etc
    • 完美运行!非常感谢。不过有一个问题:添加!i.ContainsGenericParameters 的动机是什么?
    • !i.ContainsGenericParameters 不包括class C&lt;T&gt; : ITarget&lt;T&gt; { ... }
    • @Luke:我认为你提到的限制很好,因为我只有一个T 的实现者,用于任何合适的TITarget&lt;T&gt;。不过,出于好奇,是否可以让ToDictionary 调用创建一个合适类型的list 作为其值,而不是仅创建一个类型?
    • @James:您可以调用ToLookup 来生成Lookup&lt;K,V&gt;,或者您可以使用GroupBy 然后生成Dictionary&lt;K,List&lt;V&gt;&gt; 或类似的东西。我已经用一些细节更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    相关资源
    最近更新 更多