Reputation: 542
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.
Upvotes: 4
Views: 465
Reputation: 186803
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();
Upvotes: 2
Reputation: 1797
Have Config.ClassToUse return a Type of your derived class rather than an integer identifying it.
Then your code can be shortened to:
BaseClass myclass = System.Activator.CreateInstance(Config.ClassToUse)
Upvotes: 0