如何查找程序集中的所有类,这些类是通用抽象类的实例并实现某个接口

时间:2017-11-03 13:01:59

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

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

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

一个具体的例子:
我有bellow接口和Middleware-Class:

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();
    }
}

2 个答案:

答案 0 :(得分:2)

你的问题实际上非常复杂。
问题是你的类派生自泛型类,其泛型参数实现了IHttpHandler。

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

所以在你的情况下:

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

这就是你如何得到这份清单。

答案 1 :(得分:-1)

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

internal Context context;
internal DbSet<Tariff> dbSet;

public TariffService() // the `TariffService` class is the place where I call 
                       // `GetFilteredPublished`
{
    context = new Context();
    dbSet = context.Set<Tariff>();
}

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

 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);
            }
        }

请参阅:Check if a class is derived from a generic class

用法:IsSubclassOfRawGeneric(typeof(HandlerMiddleware&lt;&gt;),typeToCheck)