给定特定的接口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)
.[???];
什么空白?
最佳答案
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
抱怨您可以这样做的情况。 t两次添加相同的密钥。如果确实需要一对多映射,那么可以使用几个选项。
使用
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());