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