Как найти все классы в сборке, которые являются экземпляром общего абстрактного класса и реализовать определенный интерфейс

Вопрос:

Как я могу найти все классы в сборке, которые являются экземпляром общего абстрактного класса и реализовать определенный интерфейс?

Заметка:
Интерфейс также может быть реализован в классе, который унаследован от другого класса, который реализует интерфейс.

Конкретный пример:
У меня есть интерфейс и Middleware-класс:

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

Лучший ответ:

Ваша проблема на самом деле довольно сложна.
Проблема в том, что ваш класс получен из общего класса, общий аргумент которого реализует 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

И как вы получите этот список.

Ответ №1

Это дает вам все классы, которые реализуют 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;
}

см.: Проверьте, является ли класс производным от общего класса

Использование: IsSubclassOfRawGeneric (typeof (HandlerMiddleware <>), typeToCheck)

Оцените статью
TechArks.Ru
Добавить комментарий