2011-12-27 100 views
29

如何獲取實現特定開放泛型類型的所有類型?獲取實現特定開放泛型類型的所有類型

例如:

public interface IUserRepository : IRepository<User> 

找到實現IRepository<>所有類型。

public static IEnumerable<Type> GetAllTypesImplementingOpenGenericType(Type openGenericType, Assembly assembly) 
{ 
    ... 
} 

回答

42

這將返回所有繼承泛型基類的類型。不是所有繼承通用接口的類型。

var AllTypesOfIRepository = from x in Assembly.GetAssembly(typeof(AnyTypeInTargetAssembly)).GetTypes() 
let y = x.BaseType 
where !x.IsAbstract && !x.IsInterface && 
y != null && y.IsGenericType && 
y.GetGenericTypeDefinition() == typeof(IRepository<>) 
select x; 

這將返回所有類型,包括接口,摘要,並且在其繼承鏈的開放式泛型類型的具體類型。

public static IEnumerable<Type> GetAllTypesImplementingOpenGenericType(Type openGenericType, Assembly assembly) 
{ 
    return from x in assembly.GetTypes() 
      from z in x.GetInterfaces() 
      let y = x.BaseType 
      where 
      (y != null && y.IsGenericType && 
      openGenericType.IsAssignableFrom(y.GetGenericTypeDefinition())) || 
      (z.IsGenericType && 
      openGenericType.IsAssignableFrom(z.GetGenericTypeDefinition())) 
      select x; 
} 

這第二個方法就可以找到ConcreteUserRepoIUserRepository在這個例子:

public interface ConcreteUserRepo : IUserRepository 
{} 

public interface IUserRepository : IRepository<User> 
{} 

public interface IRepository<User> 
{} 

public class User 
{} 
+2

是的,但是隻有當它在同一個程序集中時纔會得到concreterepo和irepo。但這絕對沒問題。 – Rookian 2011-12-27 15:22:53

+0

好抓!我們必須小心加載所有相關的程序集,而不僅僅是掃描當前加載的程序集。下面是關於加載所有程序集的一個SO:http://stackoverflow.com/questions/2384592/c-net-is-there-a-way-to-force-all-referenced-assemblies-to-be- load-into- – 2011-12-27 15:42:18

+0

typeof(IRepository <>)僅適用於泛型類型具有單個泛型參數的情況。對於具有多個泛型類型參數的類型的任何想法? – dotnetguy 2015-12-08 00:29:59

2

你可以嘗試

openGenericType.IsAssignableFrom(myType.GetGenericTypeDefinition()) 

myType.GetInterfaces().Any(i => i.Type == openGenericType) 
3

不使用LINQ實現的解決方案,搜索泛型和非泛型接口,將返回類型過濾爲類。

public static class SampleCode 
{ 
    public static void Main() 
    { 
     IList<Type> loadableTypes; 

     // instance the dummy class used to find the current assembly 
     DummyClass dc = new DummyClass(); 

     loadableTypes = GetClassesImplementingAnInterface(dc.GetType().Assembly, typeof(IMsgXX)).Item2; 
     foreach (var item in loadableTypes) {Console.WriteLine("1: " + item);} 
     // print 
     // 1: Start2.MessageHandlerXY 

     loadableTypes = GetClassesImplementingAnInterface(dc.GetType().Assembly, typeof(IHandleMessageG<>)).Item2; 
     foreach (var item in loadableTypes) { Console.WriteLine("2: " + item); } 
     // print 
     // 2: Start2.MessageHandlerXY 
     // 2: Start2.MessageHandlerZZ 
    } 

    ///<summary>Read all classes in an assembly that implement an interface (generic, or not generic)</summary> 
    // 
    // some references 
    // return all types implementing an interface 
    // http://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface/12602220#12602220 
    // http://haacked.com/archive/2012/07/23/get-all-types-in-an-assembly.aspx/ 
    // http://stackoverflow.com/questions/7889228/how-to-prevent-reflectiontypeloadexception-when-calling-assembly-gettypes 
    // return all types implementing a generic interface 
    // http://stackoverflow.com/questions/33694960/find-all-types-implementing-a-certain-generic-interface-with-specific-t-type 
    // http://stackoverflow.com/questions/8645430/get-all-types-implementing-specific-open-generic-type 
    // http://stackoverflow.com/questions/1121834/finding-out-if-a-type-implements-a-generic-interface 
    // http://stackoverflow.com/questions/5849210/net-getting-all-implementations-of-a-generic-interface 
    public static Tuple<bool, IList<Type>> GetClassesImplementingAnInterface(Assembly assemblyToScan, Type implementedInterface) 
    { 
     if (assemblyToScan == null) 
      return Tuple.Create(false, (IList<Type>)null); 

     if (implementedInterface == null || !implementedInterface.IsInterface) 
      return Tuple.Create(false, (IList<Type>)null); 

     IEnumerable<Type> typesInTheAssembly; 

     try 
     { 
      typesInTheAssembly = assemblyToScan.GetTypes(); 
     } 
     catch (ReflectionTypeLoadException e) 
     { 
      typesInTheAssembly = e.Types.Where(t => t != null); 
     } 

     IList<Type> classesImplementingInterface = new List<Type>(); 

     // if the interface is a generic interface 
     if (implementedInterface.IsGenericType) 
     { 
      foreach (var typeInTheAssembly in typesInTheAssembly) 
      { 
       if (typeInTheAssembly.IsClass) 
       { 
        var typeInterfaces = typeInTheAssembly.GetInterfaces(); 
        foreach (var typeInterface in typeInterfaces) 
        { 
         if (typeInterface.IsGenericType) 
         { 
          var typeGenericInterface = typeInterface.GetGenericTypeDefinition(); 
          var implementedGenericInterface = implementedInterface.GetGenericTypeDefinition(); 

          if (typeGenericInterface == implementedGenericInterface) 
          { 
           classesImplementingInterface.Add(typeInTheAssembly); 
          } 
         } 
        } 
       } 
      } 
     } 
     else 
     { 
      foreach (var typeInTheAssembly in typesInTheAssembly) 
      { 
       if (typeInTheAssembly.IsClass) 
       { 
        // if the interface is a non-generic interface 
        if (implementedInterface.IsAssignableFrom(typeInTheAssembly)) 
        { 
         classesImplementingInterface.Add(typeInTheAssembly); 
        } 
       } 
      } 
     } 
     return Tuple.Create(true, classesImplementingInterface); 
    } 
} 

public class DummyClass 
{ 
} 

public interface IHandleMessageG<T> 
{ 
} 

public interface IHandleMessage 
{ 
} 

public interface IMsgXX 
{ 
} 

public interface IMsgXY 
{ 
} 

public interface IMsgZZ 
{ 
} 

public class MessageHandlerXY : IHandleMessageG<IMsgXY>, IHandleMessage, IMsgXX 
{ 
    public string Handle(string a) 
    { 
     return "aaa"; 
    } 
} 

public class MessageHandlerZZ : IHandleMessageG<IMsgZZ>, IHandleMessage 
{ 
    public string Handle(string a) 
    { 
     return "bbb"; 
    } 
}