我以此为我的班级签名:
public class LocationRule : IRule<Location>
我正在尝试使用reflection
访问IRule
的实现类型。
使用此代码
Assembly.GetTypes()
.Where(type => typeof(IRule<Location>).IsAssignableFrom(type)
&& !type.IsInterface)
我可以获得继承IRule
特定实现的类。但是,无法像这样动态地将类型插入此expression
。
Assembly.GetTypes()
.Where(type => typeof(IRule<typeof(AnotherClass)>).IsAssignableFrom(type)
&& !type.IsInterface)
是否可以找到所有实现IRule<>
的类,然后找出所有实现的类型?
public class LocationRule : IRule<Location>
public class NameRule : IRule<Name>
有没有办法掌握这些类型的每一种?名称和位置,因此我可以将它们放在Dictionary<TypeOfIRuleGeneric, TypeOfRuleClass>
中,即键=位置,值= LocationRule?
谢谢。
答案 0 :(得分:3)
您正在寻找所有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
是第一个(也是唯一的假设)与{{1}实现的IRule<T>
类型匹配};或者,如果类型未实现TypeOfRuleClass
,则为null
IRule<T>
过滤掉未实现Where
的候选类型IRule<T>
创建所需的字典,其中的键为ToDictionary
,其值为通用类型参数。答案 1 :(得分:0)
如果要获取实现特定接口的所有类型,可以执行以下操作:
public interface IMyInterface { }
public class MyClass: IMyInterface { }
//...
var types = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => !t.IsInterface && t.GetInterfaces().Contains(typeof(IMyInterface)))
.ToList();
此处types
中将填充MyClass
。