简体   繁体   中英

Workaround for casting concrete to base generic abstract class

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM