Nicholas King
Nicholas King

Reputation: 938

Detecting all concrete implementions of interfaces at run time

I'm trying to create some code that detects all concrete implementations of an interface within c#. However I dont believe the problem I am facing is confined to c# and is a general oop question.

I want to do the detection at runtime so I have the ability to expand the implementations of the interface at a future date.

What options/approaches are available to me in order to achieve this?

for example

public interface IAnimal{
 void MakeNoise();
}
public class Dog : IAnimal{
  public void MakeNoise()
  {
    Console.WriteLine("WOOF");
  }
}
public class Cat : IAnimal{
  public void MakeNoise()
  {
    Console.WriteLine("Meow");
  }
}
public class AnimalInstanceController{
  /*Im trying to populate this with all classes that implement IAnimal 
  */   
  public IEnumerable<IAnimal> {get;set;}
}

Thanks

Nicholas

Upvotes: 1

Views: 296

Answers (4)

Martin Ernst
Martin Ernst

Reputation: 5679

You can relatively easily do this using reflection, eg:

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var allTypes = assemblies.SelectMany(x => x.GetTypes());
        var implTypes = allTypes.Where(t => !t.IsInterface && !t.IsAbstract)
                 .Where(t => typeof (IAnimal).IsAssignableFrom(t));
        var animals = implTypes.Select(t => (IAnimal) Activator.CreateInstance(t))
                               .ToArray();

However there are a number of concerns:

  1. if you have any dependencies in the constructors, it can become quite complicated to resolve these
  2. how do you determine which assemblies to probe? the example above only probes the already loaded assemblies
  3. how do you deal with constructor exceptions?

I would suggest looking at a dependency injection / inversion of control container such as Castle Windsor along with automatic registration, eg:

 container.Register(AllTypes.FromAssemblyContaining<IAnimal>().BasedOn<IAnimal>());

There are various options of specifying which assemblies to scan, and if you use installers, you can make your system quite extensible.

Upvotes: 1

vc 74
vc 74

Reputation: 38179

You could do something like the following:

var implementations = new List<Type>();
foreach (Assembly assembly in <collection of assemblies you want to scan>)
{
  foreach (Type type in assembly.GetTypes())
  {
    if (type.GetInterfaces().Contains(typeof(IAnimal)))
    {
      implementations.Add(type);
    }
  }
}

Or use a DI container like Autofac

Upvotes: 4

Tigran
Tigran

Reputation: 62246

You can use Type.IsAssignableFrom information of a concrete type's implementation to see if it implements an interface (can be assigned to it so).

The good consise implementation can be like this:

var type = typeof(IMyInteraface);
var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

which you can find in accepted answer of: Getting all types that implement an interface

This is naturally looks only into a types of a current domain.

Upvotes: 0

PeteH
PeteH

Reputation: 2454

I could see how you could do this using reflection - going through from an assembly to its classes, then interrogating each to see if it could be cast to IWhatever - but of course this approach while not c#-specific is certainly .net-specific.

Any use to you?

Upvotes: 0

Related Questions