2

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.

9
  • 1
    Can you show us the class declaration for the class it instantiates, and also the definition of DespatchBasePlugin<>? Commented Feb 2, 2018 at 12:04
  • Updated, thanks John. I missed out the base classes of the base class, it goes about 4 levels deep, not sure if you need all of them? Commented Feb 2, 2018 at 12:07
  • 1
    I think that's enough. Let me find the correct SO post to help you. Commented Feb 2, 2018 at 12:07
  • 1
    Possible duplicate of Casting to Generic base class failing Commented Feb 2, 2018 at 12:11
  • 1
    @tonyenkiducx Here's an older article from codeproject codeproject.com/Articles/1052356/… maybe that helps. I do not write the whole stuff again :) Btw. what John wrote looks similar. Commented Feb 2, 2018 at 12:49

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I realise this is terrible, but I'm thinking I'll have to add an interface "wrapper", and then I'd have to cast the plugin to the BasePlugin type when I use it. It's legacy code....54 projects in a solution....Can't rewrite all of it.
Marking as answer.. Not marking it as duplicate because I believe this question and answer are better than the other one. Your answer is much more explicit and shows a solution rather than just pointing to an MSDN article.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.