How do I put all types implementing a certain generic interface in a dictionary?
Given a particular interface ITarget<T>
and a particular type myType
, here's how you would determine T
if myType
implements ITarget<T>
. (This code snippet is taken from the answer to an earlier question.)
foreach (var i in myType.GetInterfaces ())
if (i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ITarget<>))
return i.GetGenericArguments ()[0] ;
However, this only checks a single type, myType
. How would I create a dictionary of all such type parameters, where the key is T
开发者_Python百科 and the value is myType
? I think it would look something like this:
var searchTarget = typeof(ITarget<>);
var dict = Assembly.GetExecutingAssembly().[???]
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == searchTarget)
.[???];
What goes in the blanks?
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);
Note that if you have multiple classes implementing ITarget<>
and using the same generic type argument -- for example, class Foo : ITarget<string>
and class Bar : ITarget<string>
-- then the ToDictionary
call will fail with an ArgumentException
complaining that you can't add the same key twice.
If you do need a one-to-many mapping then you have a couple of options available.
Use
ToLookup
rather thanToDictionary
to generate aLookup<K,V>
:var dict = Assembly.GetExecutingAssembly() .GetTypes() .SelectMany(/* ... */) .ToLookup(x => x.Key, x => x.Value);
If you prefer to work with something like a
Dictionary<K,List<V>>
then you could do this:var dict = Assembly.GetExecutingAssembly() .GetTypes() .SelectMany(/* ... */) .GroupBy(x => x.Key, x => x.Value) .ToDictionary(g => g.Key, g => g.ToList());
精彩评论