繁体   English   中英

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

[英]Is there a way to get the type of an inherited generic class using 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?

谢谢。

您正在寻找所有IRule<T>类型之间的某种“共通性”。 您可以按照dcg的建议定义基本接口,但这不会引出问题的第二部分,在该部分中您想提取泛型类型参数并将其插入字典中。

有一个称为通用类型定义的东西,它表示“精简”通用类型,而所有通用类型参数均已删除。 您可以将其用作“公共性”。

typeof(IRule<Location>).GetGenericTypeDefinition() // MyApp.IRule`1[T]

但是C#允许您实际上在typeof使用未指定的泛型类型,以便更简洁地为您提供相同的功能:

typeof(IRule<>) // compiles! Also gives MyApp.IRule`1[T]

IsAssignableFrom在这里将不会有用,因为您无法实例化开始时未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<>的通用类型参数,值是实现它的类。 我将假设您最多具有一个针对特定T实现IRule<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是第一个(也是唯一的假设)与TypeOfRuleClass实现的IRule<T>类型匹配的TypeOfRuleClass 或,如果类型未实现IRule<T>则为null
  • 第二个Where过滤掉未实现IRule<T>候选类型
  • ToDictionary创建所需的字典,其中的键是TypeOfRuleClass ,值是通用类型参数。

如果要获取实现特定接口的所有类型,可以执行以下操作:

public interface IMyInterface { }

public class MyClass: IMyInterface { }

//...
var types = Assembly.GetExecutingAssembly()
    .GetTypes()
    .Where(t => !t.IsInterface && t.GetInterfaces().Contains(typeof(IMyInterface)))
    .ToList();

在这里, types将用MyClass填充。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM