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.