【问题标题】:How to find all classes in an assembly that are an instance of a generic abstract class and implement a certain interface如何在程序集中查找作为通用抽象类实例的所有类并实现某个接口
【发布时间】:2023-03-28 08:36:01
【问题描述】:

如何在程序集中找到作为通用抽象类的实例并实现某个接口的所有类?

注意:
该接口也可以在从另一个实现该接口的类继承的类中实现。

一个具体的例子:
我有波纹管接口和中间件类:

public interface IHttpHandler
{
    bool IsReusable { get; }
    void ProcessRequest(HttpContext context);
}

public abstract class HandlerMiddleware<T> where T: IHttpHandler
{

    private readonly RequestDelegate _next;

    public HandlerMiddleware()
    { }

    public HandlerMiddleware(RequestDelegate next)
    {
        _next = next;
    }


    public async Task Invoke(HttpContext context)
    {    
        await SyncInvoke(context);
    }


    public Task SyncInvoke(HttpContext context)
    {
        // IHttpHandler handler = (IHttpHandler)this;
        T handler = System.Activator.CreateInstance<T>();

        handler.ProcessRequest(context);
        return Task.CompletedTask;
    }


} // End Abstract Class HandlerMiddleware

我怎样才能找到像 HelloWorldHandler 这样实现抽象类并实现 IHttpHandler 的所有类。

请注意,HandlerMiddleware 是通用的。
它应该找到所有处理程序,例如HelloWorldHandler1 和 HelloWorldHandler2。

[HandlerPath("/hello")]
public class HelloWorldHandler 
    : HandlerMiddleware<HelloWorldHandler>, IHttpHandler
{
    public HelloWorldHandler() :base() { }
    public HelloWorldHandler(RequestDelegate next):base(next) { }

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        //await context.Response.WriteAsync("Hello World!");
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes("hello world");
        context.Response.Body.Write(buffer, 0, buffer.Length);
    }

    bool IHttpHandler.IsReusable
    {
        get
        {
            return false;
        }
    }

}

如果该方法也找到此构造,则加分:

[HandlerPath("/hello2")]
public class HelloWorldHandler2
: HandlerMiddleware<Middleman>
{

    public HelloWorldHandler2() :base() { }
    public HelloWorldHandler2(RequestDelegate next):base(next) { }

}


public class Middleman
    : IHttpHandler
{
    bool IHttpHandler.IsReusable => throw new NotImplementedException();

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
        throw new NotImplementedException();
    }
}

【问题讨论】:

  • 结构 HandlerMiddleware 的所有类,其中 已实现 IHttpHandler(无论实现本身是否抛出未实现)。
  • 这个“发现”的上下文是什么?您是在寻找有关如何使用 Visual Studio 的建议,还是想编写在运行时执行此搜索的反射代码?
  • @Damien_The_Unbeliever:问得好。我的意思是在运行时搜索。
  • 只需使用typeof(HandlerMiddleware).IsAssignableFrom(type) &amp;&amp; typeof(IHttpHandler).IsAssignableFrom(type)。展开成typeof(type-in-assembly).Assembly.GetTypes().Where(t =&gt; typeof(HandlerMiddleware).IsAssignableFrom(t)&amp;&amp; typeof(IHttpHandler).IsAssignableFrom(type)).ToArray();

标签: c# asp.net .net asp.net-core .net-core


【解决方案1】:

您的问题实际上很难掌握。
问题是你的类是从一个泛型类派生的,它的泛型参数实现了 IHttpHandler。

您需要获取继承的(基本)类型(因为您继承自它)。
那是泛型类型,因此您需要检查它是否是泛型类型。
如果是,则需要获取泛型类型(GetGenericTypeDefinition)。
然后您需要检查泛型类型是否为 HandlerMiddleware
类型 然后你需要从泛型类型中获取参数。
然后您需要检查第一个通用参数(如果有的话)。
然后您需要检查该泛型参数的类型(或其派生基)是否实现了相关接口。

所以在你的情况下:

var ls = FindDerivedTypes(t.Assembly, typeof(HandlerMiddleware<>), typeof(IHttpHandler));
        System.Console.WriteLine(ls);



public static List<System.Type> FindDerivedTypes(Assembly assembly
    , System.Type typeToSearch
    ,System.Type neededInterface)
{
    List<System.Type> ls = new List<System.Type>();

    System.Type[] ta = assembly.GetTypes();

    int l = ta.Length;
    for (int i = 0; i < l; ++i)
    {
        if (ta[i].BaseType == null)
            continue;

        if (!ta[i].BaseType.IsGenericType)
            continue;

        // public class Middleman : IHttpHandler
        // public class HelloWorldHandler2 : HandlerMiddleware<Middleman>
        // public class HelloWorldHandler : HandlerMiddleware<HelloWorldHandler>, IHttpHandler

        var gt = ta[i].BaseType.GetGenericTypeDefinition();
        if (gt == null)
            continue;

        if (!object.ReferenceEquals(gt, typeToSearch))
            continue;

        Type[] typeParameters = ta[i].BaseType.GetGenericArguments();
        if (typeParameters == null || typeParameters.Length < 1)
            continue;

        if(neededInterface.IsAssignableFrom(typeParameters[0]))
            ls.Add(ta[i]);
    } // Next i 

    return ls;
} // End Function FindDerivedTypes

这就是您获得该列表的方式。

【讨论】:

    【解决方案2】:

    这为您提供了在当前域的程序集中实现 IHttpHandler 的所有类:

     List<Type> result = new List<Type>();
    
            var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
    
            foreach(var assem in assemblies)
            {
                var list = assem.GetExportedTypes().Where(t => t.GetInterfaces().Contains(typeof(IHttpHandler))).ToList();
    
                if (list != null && list.Count != 0)
                {
                    result.AddRange(list);
                }
            }
    

    要检查它是否派生自通用抽象类,您可以使用以下命令:

    static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
        {
            while (toCheck != null && toCheck != typeof(object))
            {
                var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
                if (generic == cur)
                {
                    return true;
                }
                toCheck = toCheck.BaseType;
            }
            return false;
        }
    

    见:Check if a class is derived from a generic class

    用法:IsSubclassOfRawGeneric(typeof(HandlerMiddleware), typeToCheck)

    【讨论】:

    • 不,你不能,因为 IsSubclassOf-Type 是通用类型。
    • 好的,为泛型添加了另一段代码
    猜你喜欢
    • 2014-08-18
    • 1970-01-01
    • 2016-02-15
    • 2014-04-05
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    相关资源
    最近更新 更多