jua*_*uan 524 c# reflection optimization lambda c#-3.0
使用反射,如何使用最少的代码获得使用C#3.0/.NET 3.5实现接口的所有类型,并最大限度地减少迭代?
这就是我想要重写的内容:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
Run Code Online (Sandbox Code Playgroud)
Dar*_*opp 773
我的将是这个在c#3.0 :)
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Run Code Online (Sandbox Code Playgroud)
基本上,迭代次数最少的是:
loop assemblies
loop types
see if implemented.
Run Code Online (Sandbox Code Playgroud)
小智 60
这对我有用.它循环遍历类并检查它们是否来自myInterface
foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
.Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
Jud*_*ngo 55
要查找实现IFoo接口的程序集中的所有类型:
var results = from type in someAssembly.GetTypes()
where typeof(IFoo).IsAssignableFrom(type)
select type;
Run Code Online (Sandbox Code Playgroud)
请注意,Ryan Rinaldi的建议不正确.它将返回0种类型.你不能写
where type is IFoo
Run Code Online (Sandbox Code Playgroud)
因为type是System.Type实例,并且永远不会是IFoo类型.而是检查是否可以从类型中分配IFoo.这将获得您的预期结果.
此外,Adam Wright的建议,目前被标记为答案,也是不正确的,并且出于同样的原因.在运行时,您将看到0种类型返回,因为所有System.Type实例都不是IFoo实现者.
ris*_*ism 54
我很欣赏这是一个非常古老的问题,但我想我会为未来的用户添加另一个答案,因为所有日期答案都使用某种形式Assembly.GetTypes
.
虽然GetTypes()确实会返回所有类型,但它并不一定意味着你可以激活它们,因此可能会抛出一个ReflectionTypeLoadException
.
无法激活类型的典型示例是返回的类型derived
来自base
但是base
在derived
与调用程序集未引用的程序集不同的程序集中定义.
所以说我们有:
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
Run Code Online (Sandbox Code Playgroud)
如果我们在ClassC
其中,AssemblyC
那么按照接受的答案做一些事情:
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Run Code Online (Sandbox Code Playgroud)
然后它会抛出一个ReflectionTypeLoadException
.
这是因为没有参考AssemblyA
,AssemblyC
你将无法:
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
Run Code Online (Sandbox Code Playgroud)
换句话说ClassB
,不能加载,这是对GetTypes的调用检查和抛出的东西.
因此,为了安全地限定可加载类型的结果集,然后根据这个Phil Haacked文章获取程序集中的所有类型和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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
var it = typeof (IMyInterface);
return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}
Run Code Online (Sandbox Code Playgroud)
hil*_*tuk 20
其他答案在这里使用IsAssignableFrom
.您也可以使用FindInterfaces
从System
命名空间,如所描述这里.
下面是一个示例,它检查当前正在执行的程序集文件夹中的所有程序集,查找实现某个接口的类(为清楚起见,避免使用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();
}
Run Code Online (Sandbox Code Playgroud)
如果要匹配多个接口,可以设置接口列表.
ang*_*son 18
循环遍历所有已加载的程序集,遍历所有类型,并检查它们是否实现了接口.
就像是:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里看到了很多过于复杂的答案,人们总是告诉我我倾向于使事情变得过于复杂。同样以IsAssignableFrom
解决OP问题为目的的方法也是错误的!
这是我的示例,它从应用程序域中选择所有程序集,然后获取所有可用类型的平面列表并检查每个类型的接口列表是否匹配:
public static IEnumerable<Type> GetImplementingTypes(this Type itype)
=> AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
.Where(t => t.GetInterfaces().Contains(itype));
Run Code Online (Sandbox Code Playgroud)
小智 8
这对我有用(如果你希望你可以在查找中排除系统类型):
Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
t => lookupType.IsAssignableFrom(t) && !t.IsInterface);
Run Code Online (Sandbox Code Playgroud)
其他答案不适用于通用接口。
这样做,只需将 typeof(ISomeInterface) 替换为 typeof (T)。
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();
Run Code Online (Sandbox Code Playgroud)
所以与
AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
Run Code Online (Sandbox Code Playgroud)
我们得到了所有的程序集
!x.IsInterface && !x.IsAbstract
Run Code Online (Sandbox Code Playgroud)
用于排除接口和抽象接口和
.Select(x => x.Name).ToList();
Run Code Online (Sandbox Code Playgroud)
将它们列在列表中。
迄今为止发布的所有答案都考虑了太少或太多的程序集。您只需检查引用包含该接口的程序集的程序集。这可以最大限度地减少不必要运行的静态构造函数的数量,并节省大量时间,并在第三方程序集的情况下节省可能出现的意外副作用。
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);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我刚刚看到编辑,以澄清原始问题是减少迭代/代码,这一切都很好,作为一个练习,但在现实世界的情况下,你将希望最快的实现,无论如何底层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;
}
Run Code Online (Sandbox Code Playgroud)
我承认,它不漂亮.
归档时间: |
|
查看次数: |
240924 次 |
最近记录: |