Как поместить все типы, реализующие определенный универсальный интерфейс, в словарь? - PullRequest
3 голосов
/ 24 мая 2010

Для конкретного интерфейса ITarget<T> и определенного типа myType, вот как вы бы определили T, если myType реализует ITarget<T>. (Этот фрагмент кода взят из ответа на на предыдущий вопрос .)

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)
             .[???];

Что происходит в пробелах?

1 Ответ

6 голосов
/ 24 мая 2010
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());
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...