Вы ищете какую-то "общность" между всеми IRule<T>
типами. Вы можете определить базовый интерфейс, как предлагает dcg, но это не приведет ко второй части вашего вопроса, где вы хотите извлечь параметры универсального типа и вставить их в словарь.
Существует вещь, называемая определением универсального типа , которая представляет «урезанный» универсальный тип со всеми удаленными параметрами универсального типа. Вместо этого вы можете использовать это как «общность».
typeof(IRule<Location>).GetGenericTypeDefinition() // MyApp.IRule`1[T]
Но C # позволяет вам на самом деле использовать неопределенный универсальный тип в typeof
, чтобы дать вам то же самое более кратко:
typeof(IRule<>) // compiles! Also gives MyApp.IRule`1[T]
IsAssignableFrom
здесь не пригодится, потому что вы не можете создать экземпляр неструктурированного универсального типа для начала.
Я создал вспомогательный метод, который получает все общие интерфейсы, реализованные с помощью типа:
public static IEnumerable<Type> GetGenericInterfaces(this Type type)
{
return type.GetInterfaces().Where(t => t.IsGenericType);
}
Вот еще один метод, который сообщает мне, могу ли я создать тип из заданного определения универсального типа:
public static bool IsConstructableFrom(this Type type, Type genericTypeDefinition)
{
return type.IsConstructedGenericType &&
(type.GetGenericTypeDefinition() == genericTypeDefinition);
}
Теперь ваш запрос будет:
var types = assembly.GetTypes().Where(type =>
!type.IsInterface &&
type.GetGenericInterfaces().Any(generic => generic.IsConstructableFrom(typeof(IRule<>))))
.ToArray();
Но, в конечном итоге, вам нужно Dictionary<TypeOfIRuleGeneric, TypeOfRuleClass>
, где ключ - это параметр общего типа IRule<>
, а значение - это класс, который его реализует. Я предполагаю, что у вас будет не более одного класса, который реализует IRule<T>
для определенного T
(верно ли это предположение?). Я также предполагаю, что каждый класс будет реализовывать не более одного IRule<T>
(верно ли это предположение?).
Есть много способов сделать эту часть. Я придумал это:
var dict = assembly.GetTypes()
.Where(type => !type.IsInterface)
.Select(type => new
{
TypeOfRuleClass = type,
IRuleInterface = type
.GetGenericInterfaces().FirstOrDefault(generic => generic.IsConstructableFrom(typeof(IRule<>)))
})
.Where(t => t.IRuleInterface != null)
.ToDictionary(t => t.TypeOfRuleClass, t => t.IRuleInterface.GetGenericArguments()[0]);
- Первый
Where
отфильтровывает интерфейсы из возможных типов
-
Select
преобразует каждый тип-кандидат в кортеж (TypeOfRuleClass, IRuleInterface)
, где IRuleInterface
- это первый (и единственный, по предположению) совпадающий тип IRule<T>
, реализованный TypeOfRuleClass
; или null
, если тип не реализует IRule<T>
- Второй
Where
отфильтровывает типы кандидатов, которые не реализуют IRule<T>
-
ToDictionary
создает нужный словарь, ключом которого является TypeOfRuleClass
, а значением является параметр универсального типа.