获取实现接口的所有types
使用reflection,我怎样才能获得所有types的实现与C#3.0 / .NET 3.5与最less的代码,并最小化迭代?
这是我想重写的内容:
foreach (Type t in this.GetType().Assembly.GetTypes()) if (t is IMyInterface) ; //do stuff
我的将在c#3.0中为此:)
var type = typeof(IMyInterface); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p));
基本上,最小的迭代总是:
loop assemblies loop types see if implemented.
要在实现IFoo接口的程序集中查找所有types:
var results = from type in someAssembly.GetTypes() where typeof(IFoo).IsAssignableFrom(type) select type;
请注意Ryan Rinaldi的build议是不正确的。 它将返回0types。 你不能写
where type is IFoo
因为type是一个System.Type实例,永远不会是IFootypes的。 而是检查IFoo是否可以从types中分配。 这将得到您的预期结果。
此外,亚当·赖特(Adam Wright)的build议目前也被认为是答案,也是不正确的,同样的原因。 在运行时,你会看到0个types返回,因为所有的System.Type实例都不是IFoo实现者。
这对我有效。 它循环虽然类和检查,看它们是否从myInterface derrived
foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes() .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) { //do stuff }
我很欣赏这是一个非常古老的问题,但我想我会为未来的用户添加另一个答案,因为所有迄今为止的答案使用某种forms的Assembly.GetTypes
。
虽然GetTypes()确实会返回所有types,但并不一定意味着可以激活它们,因此可能会抛出ReflectionTypeLoadException
。
不能激活一个types的典型例子是当返回的types是从base
derived
,但是base
是在derived
的不同的程序集中定义的,调用程序集没有引用的程序集。
所以说我们有:
Class A // in AssemblyA Class B : Class A, IMyInterface // in AssemblyB Class C // in AssemblyC which references AssemblyB but not AssemblyA
如果在ClassC
中的ClassC
,我们按照接受的答案做一些事情:
var type = typeof(IMyInterface); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p));
然后它会抛出一个ReflectionTypeLoadException
。
这是因为在AssemblyC
没有提及AssemblyA
,您将无法:
var bType = typeof(ClassB); var bClass = (ClassB)Activator.CreateInstance(bType);
换句话说, ClassB
不可加载 ,这是对GetTypes的调用进行检查和抛出的东西。
因此,为了安全地限定可加载types的结果集,然后按照Phil Haacked的文章“在Assembly中获取所有types”和Jon Skeet代码,您可以执行如下操作:
public static class TypeLoaderExtensions { public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) { if (assembly == null) throw new ArgumentNullException("assembly"); try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); } } }
接着:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) { var it = typeof (IMyInterface); return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList(); }
其他答案在这里使用IsAssignableFrom
。 您也可以使用System
命名空间中的FindInterfaces
,如此处所述。
下面是一个例子,它检查当前正在执行的程序集文件夹中的所有程序集,查找实现某个接口的类(避免使用LINQ来清晰)。
static void Main() { const string qualifiedInterfaceName = "Interfaces.IMyInterface"; var interfaceFilter = new TypeFilter(InterfaceFilter); var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var di = new DirectoryInfo(path); foreach (var file in di.GetFiles("*.dll")) { try { var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName); foreach (var type in nextAssembly.GetTypes()) { var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName); if (myInterfaces.Length > 0) { // This class implements the interface } } } catch (BadImageFormatException) { // Not a .net assembly - ignore } } } public static bool InterfaceFilter(Type typeObj, Object criteriaObj) { return typeObj.ToString() == criteriaObj.ToString(); }
如果要匹配多个接口,可以设置接口列表。
遍历所有加载的程序集,遍历所有types,并检查它们是否实现了接口。
就像是:
Type ti = typeof(IYourInterface); foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type t in asm.GetTypes()) { if (ti.IsAssignableFrom(t)) { // here's your type in t } } }
这对我有用(如果你希望你可以在查找中排除系统types):
Type lookupType = typeof (IMenuItem); IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where( t => lookupType.IsAssignableFrom(t) && !t.IsInterface);
编辑:我刚刚看到编辑澄清,原来的问题是减less迭代/代码,这一切都很好,作为一个练习,但在现实世界的情况下,你会想要最快的实现,无论底层LINQ看起来有多酷。
这是我的Utils方法迭代通过加载的types。 它处理常规类以及接口,如果您正在寻找自己/第三方代码库中的实现,则excludeSystemTypes选项将大大加快速度。
public static List<Type> GetSubclassesOf(this Type type, bool excludeSystemTypes) { List<Type> list = new List<Type>(); IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator(); while (enumerator.MoveNext()) { try { Type[] types = ((Assembly) enumerator.Current).GetTypes(); if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) { IEnumerator enumerator2 = types.GetEnumerator(); while (enumerator2.MoveNext()) { Type current = (Type) enumerator2.Current; if (type.IsInterface) { if (current.GetInterface(type.FullName) != null) { list.Add(current); } } else if (current.IsSubclassOf(type)) { list.Add(current); } } } } catch { } } return list; }
这不是很美,我承认。
没有简单的方法(在性能方面)做你想做的事情。
reflection主要用于组件和types,因此您必须获取程序集的所有types,并查询它们以获取正确的界面。 这是一个例子:
Assembly asm = Assembly.Load("MyAssembly"); Type[] types = asm.GetTypes(); Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);
这将为您带来在Assembly MyAssembly中实现IMyInterface的所有types
你可以使用一些LINQ来获取列表:
var types = from type in this.GetType().Assembly.GetTypes() where type is ISomeInterface select type;
但是,真的,这是更可读?