Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiate all classes implementing a specific interface

Tags:

I have an interface IExample, and a set of classes ClassOne, ClassTwo and ClassThree, all defined in different namespaces. I will possibly remove either of the classes, or add a new one in a new place, at a later stage in development.

Now, I want to find all types that implement IExample at runtime, and instantiate them. (I know on beforehand that no class implementing IExample will ever need any constructor arguments, but I don't know how to specify that in code, so it's me - not the compiler - that knows...)

Is this possible? How do I go about to do it?

Update: I've now tried several of the approaches suggested, but on all of them, the line Activator.CreateInstance(type), I get a System.MissingMethodException because I "cannot create an instance of an interface." This is my code:

var tasks = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(a => a.GetTypes())
    .Where(t => typeof(IBootstrapperTask).IsAssignableFrom(t))

    // This line is where it fails
    .Select(t => Activator.CreateInstance(t) as IBootstrapperTask)

    .ToArray();
new AutoMapperBootstrapper(tasks).Initialize();

Without the as clause I don't see any exception, but I'm given an object[], and I need an IBootstrapperTask[] for the constructor on the last line in the excerpt. I've tried various ways to cast it, but none seem to work.

like image 875
Tomas Aschan Avatar asked Feb 25 '11 17:02

Tomas Aschan


People also ask

How do you instantiate an interface?

An interface can't be instantiated directly. Its members are implemented by any class or struct that implements the interface. A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or more interfaces.

How do you instantiate an interface in Java?

No, you cannot instantiate an interface. Generally, it contains abstract methods (except default and static methods introduced in Java8), which are incomplete. Still if you try to instantiate an interface, a compile time error will be generated saying “MyInterface is abstract; cannot be instantiated”.

Do you have to implement all methods of an interface Java?

Must we implement all the methods in a class that implements an interface in Java? Yes, it is mandatory to implement all the methods in a class that implements an interface until and unless that class is declared as an abstract class.

Can a class implement an interface and extend a class?

Note: A class can extend a class and can implement any number of interfaces simultaneously.


2 Answers

This can be done with Reflection. For example

var interfaceType = typeof(IExample);
var all = AppDomain.CurrentDomain.GetAssemblies()
  .SelectMany(x => x.GetTypes())
  .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
  .Select(x => Activator.CreateInstance(x));

Note: This will only create instances of IExample from assemblies loaded in the current AppDomain. This can be different than all assemblies loaded in the current process. However for many types of applications this will be equivalent.

like image 165
JaredPar Avatar answered Sep 28 '22 05:09

JaredPar


You'd need to know a list of assemblies to look in, but then LINQ makes it relatively easy:

var instances = (from assembly in assemblies
                 from type in assembly
                 where !type.IsAbstract && 
                       type.IsClass &&
                       type.IsPublic &&
                       !type.IsGenericType &&
                       typeof(IExample).IsAssignableFrom(type)
                 let ctor = type.GetConstructor(Type.EmptyTypes)
                 where ctor != null && ctor.IsPublic
                 select (IExample) Activator.CreateInstance(type))
                .ToList();

You may think of some other restrictions to add, but they're pretty easy to express :)

instances will then be a List<IExample>.

EDIT: I suspect my code will work where yours didn't, because I'm specifically excluding non-classes. My guess is that your code is trying to instantiate the interface itself, i.e. when t is typeof(IBootstrapperTask).

like image 44
Jon Skeet Avatar answered Sep 28 '22 03:09

Jon Skeet