Search code examples
c#.netreflectionsystem.reflectiondecoupling

Dynamically instantiate classes extending baseclass using reflection


For a long time I have been struggling with finding a way to dynamically instantiate all classes that extends a specific baseclass (during runtime). From what I have read, it is supposed to be done using Reflection, unfortunately I haven't figured out how yet.

My project structure looks like this:

Library
--|
  |
  --Vehicle.cs (abstract class)
  |
  --Car.cs (extending vehicle)
  |
  --Bike.cs (extending vehicle)
  |
  --Scooter.cs (extending vehicle)
  |
  --InstanceService.cs (static class)
  |
  |
ConsoleApplication
--|
  |
  --Program.cs

The InstanceService class contains a generic method which is supposed to return an IEnumerable<T> containing the instantiated classes extending Vehicle, meaning Car, Bike & Scooter.

The code posted bellow is the current state of the InstanceService class, after having tried a ton of different solutions, meaning it mostly contains tools for debugging.

InstanceService.cs

using System;
using System.Collections.Generic;

namespace Library
{
    public static class InstanceService<T>
    {
        //returns instances of all classes of type T
        public static IEnumerable<T> GetInstances()
        {

            var interfaceType = typeof(T);
            List<T> list = new List<T>();
            Console.WriteLine("Interface type: " + interfaceType.ToString());
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach(var assembly in assemblies)
            {
                Console.WriteLine("Assembly: " + assembly.ToString());
                if (assembly.GetType().IsAbstract)
                {
                    var instance = (T) Activator.CreateInstance(assembly.GetType());
                    list.Add(instance);
                }
            }
            return list;
        }
    }
}

I have also attached the code for the abstract Vehicle class as well as one of the implementations of it.

Vehicle.cs

namespace Library
{
    public abstract class Vehicle
    {
        protected float maxSpeedInKmPerHour;
        protected float weightInKg;
        protected float priceInDkk;
    }
}

Car.cs

namespace Library
{
    public class Car : Vehicle
    {

        public Car()
        {
            this.maxSpeedInKmPerHour = 1200;
            this.weightInKg = 45000;
            this.priceInDkk = 71000000;
        }
    }
}

Solution

  • I think the method that should interest you is IsAssignableFrom.

    Also, the code is much easier with LINQ, if you're allowed to use that, and since you're creating the objects one at a time, I suggest using yield return.

    static IEnumerable<T> GetInstances<T>() 
    {
        var baseType = typeof(T);
        var types = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany( a => a.GetTypes() )
            .Where
            (
                t => baseType.IsAssignableFrom(t)                  //Derives from base
                  && !t.IsAbstract                                 //Is not abstract
                  && (t.GetConstructor(Type.EmptyTypes) != null)   //Has default constructor
            );
    
    
        foreach (var t in types)
        {
            yield return (T)Activator.CreateInstance(t);
        }
    }
    

    Or if for some reason you're showing off and you want to do it with one statement:

        var types = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany( a => a.GetTypes() )
            .Where
            (
                t => typeof(T)IsAssignableFrom(t)  
                  && !t.IsAbstract 
                  && (t.GetConstructor(Type.EmptyTypes) != null) 
            )
            .Select
            (
                t => (T)Activator.CreateInstance(t)
            );