使用反射,我如何能得到所有类型的实现接口与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
当前回答
我在这里看到了太多过于复杂的答案,人们总是告诉我,我倾向于把事情复杂化。同样使用IsAssignableFrom方法来解决OP问题也是错误的!
下面是我的例子,它从应用程序域中选择所有程序集,然后它采用所有可用类型的平面列表,并检查每个类型的接口列表是否匹配:
public static IEnumerable<Type> GetImplementingTypes(this Type itype)
=> AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
.Where(t => t.GetInterfaces().Contains(itype));
其他回答
我在linq-code中得到了异常,所以我这样做(没有复杂的扩展):
private static IList<Type> loadAllImplementingTypes(Type[] interfaces)
{
IList<Type> implementingTypes = new List<Type>();
// find all types
foreach (var interfaceType in interfaces)
foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies())
try
{
foreach (var currentType in currentAsm.GetTypes())
if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract)
implementingTypes.Add(currentType);
}
catch { }
return implementingTypes;
}
其他答案在这里使用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();
}
如果需要匹配多个接口,可以设置一个接口列表。
我在这里看到了太多过于复杂的答案,人们总是告诉我,我倾向于把事情复杂化。同样使用IsAssignableFrom方法来解决OP问题也是错误的!
下面是我的例子,它从应用程序域中选择所有程序集,然后它采用所有可用类型的平面列表,并检查每个类型的接口列表是否匹配:
public static IEnumerable<Type> GetImplementingTypes(this Type itype)
=> AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
.Where(t => t.GetInterfaces().Contains(itype));
OfType Linq方法正好可以用于这种场景:
https://learn.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
编辑:我刚刚看到了编辑,澄清了最初的问题是为了减少迭代/代码,这作为一个练习是很好的,但在实际情况下,你会想要最快的实现,不管底层LINQ看起来有多酷。
下面是我的Utils方法,用于遍历加载的类型。它处理常规类和接口,如果您正在自己的/第三方代码库中寻找实现,那么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;
}
我承认,这并不漂亮。