使用反射,我如何能得到所有类型的实现接口与c# 3.0/。NET 3.5用最少的代码,最小化迭代?
这是我想重写的内容:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
使用反射,我如何能得到所有类型的实现接口与c# 3.0/。NET 3.5用最少的代码,最小化迭代?
这是我想重写的内容:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
当前回答
到目前为止,所有的答案不是考虑了太少的程序集就是考虑了太多的程序集。您只需检查引用包含该接口的程序集的程序集。这最大限度地减少了不必要地运行静态构造函数的数量,并节省了大量的时间,并且在第三方程序集的情况下可能会产生意想不到的副作用。
public static class ReflectionUtils
{
public static bool DoesTypeSupportInterface(Type type, Type inter)
{
if (inter.IsAssignableFrom(type))
return true;
if (type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == inter))
return true;
return false;
}
public static IEnumerable<Assembly> GetReferencingAssemblies(Assembly assembly)
{
return AppDomain
.CurrentDomain
.GetAssemblies().Where(asm => asm.GetReferencedAssemblies().Any(asmName => AssemblyName.ReferenceMatchesDefinition(asmName, assembly.GetName())));
}
public static IEnumerable<Type> TypesImplementingInterface(Type desiredType)
{
var assembliesToSearch = new Assembly[] { desiredType.Assembly }
.Concat(GetReferencingAssemblies(desiredType.Assembly));
return assembliesToSearch.SelectMany(assembly => assembly.GetTypes())
.Where(type => DoesTypeSupportInterface(type, desiredType));
}
public static IEnumerable<Type> NonAbstractTypesImplementingInterface(Type desiredType)
{
return TypesImplementingInterface(desiredType).Where(t => !t.IsAbstract);
}
}
其他回答
查找程序集中实现IFoo接口的所有类型:
var results = from type in someAssembly.GetTypes()
where typeof(IFoo).IsAssignableFrom(type)
select type;
请注意Ryan Rinaldi的建议是不正确的。它将返回0个类型。你不能写字
where type is IFoo
因为类型是一个系统。类型实例,并且永远不会是IFoo类型。相反,检查IFoo是否可以从类型中赋值。这将得到你预期的结果。
此外,亚当·赖特的建议,目前被标记为答案,也是不正确的,出于同样的原因。在运行时,您将看到返回0类型,因为所有System。类型实例不是IFoo实现者。
我知道这是一个非常老的问题,但我想我将为未来的用户添加另一个答案,因为迄今为止所有的答案都使用某种形式的Assembly.GetTypes。
虽然GetTypes()确实会返回所有类型,但这并不一定意味着您可以激活它们,从而可能会抛出一个reflectiontypeloadeexception异常。
无法激活类型的典型示例是,当返回的类型是从base派生的,但base定义在与派生的不同的程序集中,调用程序集没有引用该程序集。
假设我们有:
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
如果在AssemblyC中的ClassC中,我们按照接受的答案做一些事情:
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
然后它将抛出一个reflectiontypeloadeexception异常。
这是因为在AssemblyC中没有对AssemblyA的引用,您将无法:
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
换句话说,ClassB是不可加载的这是GetTypes调用检查并抛出的东西。
因此,为了安全地限定结果集为可加载类型,然后根据Phil haked的文章在一个程序集中获取所有类型和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();
}
如果需要匹配多个接口,可以设置一个接口列表。
其他答案是没有使用通用接口。
这一个做到了,只是用typeof(T)替换typeof(ISomeInterface)。
List<string> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
.Where(x => typeof(ISomeInterface).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.Select(x => x.Name).ToList();
所以,
AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
我们得到了所有的集合
!x.IsInterface && !x.IsAbstract
是用来排除接口和抽象的和
.Select(x => x.Name).ToList();
把它们列在一个列表里。
这对我很管用。它循环遍历这些类并检查它们是否派生自myInterface
foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
.Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
//do stuff
}