有没有一种方法可以使用反射来获取继承的泛型类的类型?

时间:2019-04-08 17:48:35

标签: c# reflection

我以此为我的班级签名:

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?

谢谢。

2 个答案:

答案 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