I was wondering if this is possible or not. I had a number of classes which are all derived from the same base class (BaseClass
). When I'm creating an instance, I need to decide which derived class I need to create based on a configuration value. At the moment I'm doing the below but I was hoping there would be a neater way to implement this, that would require less maintenance in case I need to add a new derived class.
BaseClass myclass;
switch (Config.ClassToUse)
{
case 1:
myclass= new DerivedClass1(Config);
break;
case 2:
myclass= new DerivedClass2(Config);
break;
case 3:
myclass = new DerivedClass3(Config);
break;
}
myclass.DoWork();
The code in the DoWork
method varies for each different instance of the class.
Hope that makes sense.
It's Config
that knows which class to create and that's why let us Config
do its job. We should get rid of magic numbers (what does 2
stand for?) and return Type
, not int
.
Quick patch is
public class Config {
...
// Get rid of this, move logic into TypeToUse
public int ClassToUse {get { ... }}
public Type TypeToUse {
get {
string name = $"DerivedClass{ClassToUse}";
// Here we scan all types in order to find out the best one. Class must be
// 1. Derived from BaseClass
// 2. Not Abstract (we want to create an instance)
// Among these classes we find the required by its name DerivedClass[1..3]
// (as a patch). You should implement a more elaborated filter
// If we have several candidates we'll take the 1st one
return AppDomain
.CurrentDomain
.GetAssemblies() // scan all assemblies
.SelectMany(asm => asm
.GetTypes() // and all types
.Where(tp => typeof(BaseClass).IsAssignableFrom(tp))) // ... for derived classes
.Where(tp => !tp.IsAbstract) //TODO: Add more filters if required
.Where(tp => tp.Name.Equals(name)) //TODO: put relevant filter here
.FirstOrDefault();
}
}
public BaseClass CreateInstance() {
Type tp = TypeToUse;
if (tp == null)
return null; // Or throw exception
return Activator.CreateInstance(tp, this) as BaseType;
}
}
Then you can put
BaseClass myclass = Config.CreateInstance();
myclass.DoWork();