鉴于特定界面ITarget<T>
和特定类型myType
,如果T
实施myType
,您可以通过以下方式确定ITarget<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)
.[???];
空白是什么?
答案 0 :(得分: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
抱怨你不能两次添加相同的密钥。
如果您确实需要一对多映射,那么您可以使用几个选项。
使用ToLookup
而非ToDictionary
生成Lookup<K,V>
:
var dict = Assembly.GetExecutingAssembly()
.GetTypes()
.SelectMany(/* ... */)
.ToLookup(x => x.Key, x => x.Value);
如果您更喜欢使用类似Dictionary<K,List<V>>
的内容,那么您可以这样做:
var dict = Assembly.GetExecutingAssembly()
.GetTypes()
.SelectMany(/* ... */)
.GroupBy(x => x.Key, x => x.Value)
.ToDictionary(g => g.Key, g => g.ToList());