【问题标题】:Create Instance of type using base class with generics使用具有泛型的基类创建类型的实例
【发布时间】:2018-02-02 12:00:55
【问题描述】:

我在我的代码中创建了一个插件系统,它从 DLLS 加载类型。我使用这段代码从加载的 DLL 中获取我想要的类型;

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

IsSubClassOfRawGeneric 寻找基类型,因为它被埋藏了几个类,代码工作并返回正确的类型。

然后我使用 Activator 创建这个类的一个实例;

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

不幸的是,这一行的强制转换创建了一个空引用。删除强制转换会返回相关类的实例,但我需要将其存储为它的基本类型。

这是正在加载的类(为简洁起见);

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

这是我希望它使用的基类(注意这个类本身有一个基类,它有好几层);

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

之前的代码使用了一个没有分配泛型的基类,并且工作得非常好。看起来像这样;

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

我确定我在做一些愚蠢的事情,请告诉我它是什么。

编辑 - 没有将其标记为重复,因为我相信这是一个比其他问题/答案更好的问题/答案,其中包含指向 MSDN 作为答案的通用链接。如果这不是使用复制系统的正确方法,请告诉我。

【问题讨论】:

  • 你能告诉我们它实例化的类的类声明,以及DespatchBasePlugin&lt;&gt;的定义吗?
  • 已更新,谢谢约翰。我错过了基类的基类,它大约有 4 级深,不知道你是否需要所有这些?
  • 我认为这就够了。让我找到正确的 SO 帖子来帮助您。
  • @tonyenkiducx 这是 codeproject codeproject.com/Articles/1052356/… 的一篇较早的文章,也许有帮助。我不再写整个东西了:)顺便说一句。约翰写的看起来很相似。

标签: c# generics activator


【解决方案1】:

您可以使用逆变来定义您的插件:

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

我已经包含了一个 BasePlugin 类,但这是可选的,您可以直接使用该接口。

【讨论】:

  • 我意识到这很糟糕,但我想我必须添加一个接口“包装器”,然后我必须在使用时将插件转换为 BasePlugin 类型。这是遗留代码......解决方案中有 54 个项目......无法全部重写。
  • 标记为答案.. 不将其标记为重复,因为我相信这个问题和答案比另一个更好。您的回答更加明确,并显示了解决方案,而不仅仅是指向 MSDN 文章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多