获取实现接口的所有类型

时间:2008-08-25 19:57:22

标签: c# optimization reflection lambda c#-3.0

使用反射,如何使用最少的代码获得使用C#3.0 / .NET 3.5实现接口的所有类型,并最大限度地减少迭代?

这就是我想重写的内容:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff

18 个答案:

答案 0 :(得分:729)

我将在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.

答案 1 :(得分:58)

这对我有用。它循环通过类并检查它们是否来自myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }

答案 2 :(得分:54)

查找实现IFoo接口的程序集中的所有类型:

var results = from type in someAssembly.GetTypes()
              where typeof(IFoo).IsAssignableFrom(type)
              select type;

请注意,Ryan Rinaldi的建议不正确。它将返回0种类型。你不能写

where type is IFoo

因为type是System.Type实例,并且永远不会是IFoo类型。而是检查是否可以从类型中分配IFoo。这将得到您的预期结果。

此外,Adam Wright的建议(目前标记为答案)也是错误的,并且出于同样的原因。在运行时,您将看到0种类型返回,因为所有System.Type实例都不是IFoo实现者。

答案 3 :(得分:46)

我很欣赏这是一个非常古老的问题,但我想我会为未来的用户添加另一个答案,因为所有日期答案都使用某种形式的Assembly.GetTypes

虽然GetTypes()确实会返回所有类型,但并不一定意味着您可以激活它们,因此可能会抛出ReflectionTypeLoadException

无法激活类型的典型示例是,返回的类型为derived basebase的定义与{{1}不同调用程序集不引用的程序集。

所以说我们有:

derived

如果在Class A // in AssemblyA Class B : Class A, IMyInterface // in AssemblyB Class C // in AssemblyC which references AssemblyB but not AssemblyA ClassC中,我们会根据接受的答案做一些事情:

AssemblyC

然后它将抛出ReflectionTypeLoadException

这是因为如果没有引用var type = typeof(IMyInterface); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p)); 中的AssemblyA,您将无法:

AssemblyC

换句话说,var bType = typeof(ClassB); var bClass = (ClassB)Activator.CreateInstance(bType); 不是可加载的,这是对GetTypes的调用检查和抛出的内容。

因此,为了安全地限定可加载类型的结果集,然后根据此Phil Haacked文章Get All Types in an AssemblyJon Skeet code,您可能会执行以下操作:

ClassB

然后:

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);
        }
    }
}

答案 4 :(得分:19)

此处的其他答案使用IsAssignableFrom。您还可以使用FindInterfaces命名空间中的System,如here所述。

这是一个示例,它检查当前正在执行的程序集文件夹中的所有程序集,查找实现某个接口的类(为清晰起见,避免使用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();
}

如果要匹配多个接口,可以设置接口列表。

答案 5 :(得分:17)

遍历所有已加载的程序集,遍历所有类型,并检查它们是否实现了接口。

类似的东西:

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
        }
    }
}

答案 6 :(得分:8)

这对我有用(如果您希望在查找中排除系统类型):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 

答案 7 :(得分:5)

编辑:我刚刚看到编辑,以澄清原始问题是减少迭代/代码,这一切都很好,作为一个练习,但在现实世界的情况下,你会想要最快实现,无论底层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;
}

这不好看,我承认。

答案 8 :(得分:4)

其他答案不适用于通用界面

这确实可以,只需将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();

所以

AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())

我们得到了所有的装配体

!x.IsInterface && !x.IsAbstract

用于排除接口和抽象接口,并且

.Select(x => x.Name).ToList();

将它们放在列表中。

答案 9 :(得分:2)

要做你想做的事,没有简单的方法(就性能而言)。

反射主要用于程序集和类型,因此您必须获取程序集的所有类型并查询它们以获得正确的接口。这是一个例子:

Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);

这将为您提供在Assembly MyAssembly

中实现IMyInterface的所有类型

答案 10 :(得分:2)

我在这里看到了太多过于复杂的答案,人们总是告诉我,我倾向于使事情变得过于复杂。同样使用IsAssignableFrom方法来解决OP问题也是错误的!

这里是我的示例,它从应用程序域中选择所有程序集,然后获取所有可用类型的平面列表并检查每种类型的接口列表是否匹配:

public static IEnumerable<Type> GetImplementingTypes(this Type itype) 
    => AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
           .Where(t => t.GetInterfaces().Contains(itype));

答案 11 :(得分:1)

选择装配体位置时更好。如果您知道所有实现的接口都在同一个Assembly.DefinedTypes中,则对大多数程序集进行过滤。

room A2

By Can Bilgin

答案 12 :(得分:1)

已经有很多有效的答案,但是我想添加另一种实现作为Type扩展和用于演示不同场景的单元测试列表:

public static class TypeExtensions
{
    public static IEnumerable<Type> GetAllTypes(this Type type)
    {
        var typeInfo = type.GetTypeInfo();
        var allTypes = GetAllImplementedTypes(type).Concat(typeInfo.ImplementedInterfaces);
        return allTypes;
    }

    private static IEnumerable<Type> GetAllImplementedTypes(Type type)
    {
        yield return type;
        var typeInfo = type.GetTypeInfo();
        var baseType = typeInfo.BaseType;
        if (baseType != null)
        {
            foreach (var foundType in GetAllImplementedTypes(baseType))
            {
                yield return foundType;
            }
        }
    }
}

此算法支持以下情况:

public static class GetAllTypesTests
{
    public class Given_A_Sample_Standalone_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleStandalone);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleStandalone),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Abstract_Base_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleBase);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Child_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleChild);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleChild),
                    typeof(SampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Base_Interface_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(ISampleBase);

            _expectedTypes =
                new List<Type>
                {
                    typeof(ISampleBase)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Child_Interface_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(ISampleChild);

            _expectedTypes =
                new List<Type>
                {
                    typeof(ISampleBase),
                    typeof(ISampleChild)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Implementation_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleImplementation);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleImplementation),
                    typeof(SampleChild),
                    typeof(SampleBase),
                    typeof(ISampleChild),
                    typeof(ISampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Interface_Instance_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        class Foo : ISampleChild { }

        protected override void Given()
        {
            var foo = new Foo();
            _sut = foo.GetType();

            _expectedTypes =
                new List<Type>
                {
                    typeof(Foo),
                    typeof(ISampleChild),
                    typeof(ISampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    sealed class SampleStandalone { }
    abstract class SampleBase { }
    class SampleChild : SampleBase { }
    interface ISampleBase { }
    interface ISampleChild : ISampleBase { }
    class SampleImplementation : SampleChild, ISampleChild { }
}

答案 13 :(得分:0)

我在linq代码中有例外,所以我这样做(没有复杂的扩展名):

private static IList<Type> loadAllTypes(Types[] interfaces)
{
    IList<Type> objects = 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)
                        objects.Add(currentType);
            }
            catch { }

    return objects;
}

答案 14 :(得分:0)

   public IList<T> GetClassByType<T>()
   {
        return AppDomain.CurrentDomain.GetAssemblies()
                          .SelectMany(s => s.GetTypes())
                          .ToList(p => typeof(T)
                          .IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface)
                          .SelectList(c => (T)Activator.CreateInstance(c));
   }

答案 15 :(得分:0)

答案 16 :(得分:0)

迄今为止发布的所有答案都考虑了太少或太多的程序集。您只需要检查引用包含接口的程序集的程序集。这最大限度地减少了不必要运行的静态构造函数的数量,并在第三方程序集的情况下节省了大量时间和可能出现的意外副作用。

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);
    }
}

答案 17 :(得分:-3)

您可以使用一些LINQ来获取列表:

var types = from type in this.GetType().Assembly.GetTypes()
            where type is ISomeInterface
            select type;

但实际上,它更具可读性吗?