Reputation: 957
I have a generic base abstract class:
public abstract class Generator<T>
{
public abstract void Start(T config);
}
Then, I have many concrete classes that inherit from base class and expect certain parameter type. Some of them:
public class AGenerator : Generator<AGeneratorConfig>
{
public override void Start(AGeneratorConfig Config) { /* some code*/ }
}
public class BGenerator : Generator<BGeneratorConfig>
{
public override void Start(BGeneratorConfig Config) { /* some code*/ }
}
Their Start()
method parameters are defined as follows:
public abstract class GeneratorConfig
{
public int CommonProperty {get; set;}
}
public class AGeneratorConfig : GeneratorConfig
{
// Some props specific for AGenerator
}
public class BGeneratorConfig : GeneratorConfig
{
// Some props specific for BGenerator
}
At last, I have a client/manager/factory-like class that handles actual generator start process with provided config, but is uses casting concrete to abstract generic class:
public class GeneratorClient
{
public static void StartGenerator<T>(T config)
{
Generator<T> generator = null;
if (config is AGeneratorConfig)
{
generator = new AGenerator() as Generator<T>; // casting to abstract base class
}
else if (config is BGeneratorConfig)
{
generator = new BGenerator() as Generator<T>; // casting to abstract base class
}
else
{
throw new NotImplementedException();
}
generator.Start(config);
}
}
My question: is there any workaround to eliminate the need of casting concrete to abstract base classes?
The most simple solution would be this:
public static void StartGenerator<T>(T config)
{
if (config is AGeneratorConfig)
{
var generator = new AGenerator();
generator.Start(config);
}
else if (config is BGeneratorConfig)
{
var generator = new BGenerator();
generator.Start(config);
}
else
{
throw new NotImplementedException();
}
}
but for each newly created concrete Generator object generator.Start(config);
needs to be repeated.
Upvotes: 1
Views: 181
Reputation: 380
You can use Reflection to call the constructor, and maybe improve you Factory in order to remove those if's.
You can use a dictionary like this:
private Dictionary<Type, Type> Diccionary;
public void CreateDicionary()
{
Diccionary = new Dictionary<Type, Type>();
Diccionary.Add(typeof(AGeneratorConfig), typeof(AGenerator));
Diccionary.Add(typeof(BGeneratorConfig), typeof(BGenerator));
}
then you can have the concrete instance with something like this:
public Generator<T> GetGenerator<T>()
{
var type = typeof(T);
if (!Diccionary.ContainsKey(type))
throw new Exception("Not found");
var typeInstance = Diccionary[type];
return (Generator<T>) Activator.CreateInstance(typeInstance);
}
And you use the code above with something similar to this:
public void StartGenerator<T>(T config)
{
var generator = GetGenerator<T>();
generator.Start(config);
}
public static void Main()
{
var gen = new GeneratorClient();
gen.CreateDicionary();
gen.StartGenerator<AGeneratorConfig>(new AGeneratorConfig());
}
Upvotes: 1
Reputation: 9650
Define the generator
just as object
and cast it to Generator<T>
only at the last call:
public static void StartGenerator<T>(T config)
{
object generator = null;
if (config is AGeneratorConfig)
{
generator = new AGenerator();
}
else if (config is BGeneratorConfig)
{
generator = new BGenerator();
}
else
{
throw new NotImplementedException();
}
((Generator<T>)generator).Start(config);
}
Upvotes: 2