2017-11-03 11 views
3

汎用抽象クラスのインスタンスであり、特定のインターフェイスを実装するすべてのクラスをアセンブリ内で見つける方法を教えてください。汎用抽象クラスのインスタンスであり、特定のインターフェイスを実装するアセンブリ内のすべてのクラスを見つける方法

注:
インターフェイスは、インターフェイスを実装する別のクラスから継承されたクラスで実装することもできます。

具体的な例:
私は怒鳴るインタフェースとミドルウェアクラスを持っている:

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などのすべてのクラスは、検索、およびIHTTPハンドラを実装することができます。

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

} 

ボーナスポイント方法は、また、この構造物を見つけた場合:かどうかを確認するには

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

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

すべてのクラスHandlerMiddleware ここで、はIHttpHandlerを実装しています(実装自体が実装されていないかどうかは関係ありません)。 – User1

+0

この "find"のコンテキストは何ですか? Visual Studioの使い方に関するアドバイスを探しているのですか、実行時にこの検索を実行するリフレクションコードを作成したいですか? –

+0

@Damien_The_Unbeliever:いい質問です。実行時に検索すると意味します。 – User1

答えて

3

あなたの問題は、実際に把握するのは非常に複雑です。
問題は、クラスがジェネリッククラスが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

これは、あなたの現在のドメインの集合体でIHTTPハンドラを実装するすべてのクラスを提供します一般的な抽象クラスから派生します。

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)

+0

いいえ、できません。なぜなら、IsSubclassOf-Typeジェネリック型です。 – User1

+0

OK、ジェネリック型の別のコードを追加しました – Reno

関連する問題