简体   繁体   中英

Create Instance of type using base class with generics

I've created a plugin system within my code, which loads types from DLLS. I grab the type I want from the loaded DLL using this code;

var type = Assembly.LoadFrom(filePath).GetTypes()
                    .FirstOrDefault(t =>
                        t.IsClass && t.IsSubclassOfRawGeneric(typeof(DespatchBasePlugin<>)));

IsSubClassOfRawGeneric hunts down the base type as it is buried several classes down, the code works and the correct type is returned.

I then create an instance of this class using Activator;

DespatchBasePlugin<XMLSettingBase> obj = Activator.CreateInstance(type, new object[] { logger }) as DespatchBasePlugin<XMLSettingBase>;

Unfortunately the cast on this line creates a null reference. Removing the cast returns an instance of the class in question, but I need to store is as its base type.

This is the class being loaded(Shortened for brevity);

public class DHLPlugin : DespatchBasePlugin<UserSetting>
{
    public DHLPlugin(BaseForm logger) : base("DHL", logger)
    {
        this.order = 10;
    }
}

And this is the base class I want it to use(Note the class itself has a base class, it goes several layers deep);

public abstract class DespatchBasePlugin<TSettings> : DespatchBase<TSettings> where TSettings : XMLSettingBase, new()

The previous code used a base class with no generic assigned to it and worked absolutely fine. It looked like this;

DespatchBasePlugin obj = Activator.CreateInstance(type, new object[] { logger }) as DespatchBasePlugin;

I'm sure I'm doing something dumb, please tell me what it is.

Edit - Not marked this as duplicate as I believe this is a better question/answer than the other which consists of a generic link to MSDN as the answer. If this is not a correct way to use the duplicate system please let me know.

You can use contravariance to define your plugin:

public class Program
{
    public static void Main()
    {
        var settings = new DerivedSettings()
        {Name = "John"};
        DerivedPlugin a = new DerivedPlugin(settings);
        IPlugin<BaseSettings> sample = (IPlugin<BaseSettings>)a;
        Console.WriteLine(sample.GetName());
    }
}

public abstract class BaseSettings
{
    public abstract string Name
    {
        get;
        set;
    }
}

public interface IPlugin<out TSettings>
    where TSettings : BaseSettings
{
    string GetName();
}

public abstract class BasePlugin<TSettings> : IPlugin<TSettings> where TSettings : BaseSettings
{
    protected readonly TSettings _settings;
    public BasePlugin(TSettings settings)
    {
        _settings = settings;
    }

    public virtual string GetName()
    {
        return _settings.Name;
    }
}

public class DerivedSettings : BaseSettings
{
    public override string Name
    {
        get;
        set;
    }
}

public class DerivedPlugin : BasePlugin<DerivedSettings>
{
    public DerivedPlugin(DerivedSettings settings): base (settings)
    {
    }
}

I've included a BasePlugin class, but this is optional and you can just directly use the interface.

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