C# 插件体系结构中的DI(Autofac):每个插件有一个单独的DI容器可以吗?

C# 插件体系结构中的DI(Autofac):每个插件有一个单独的DI容器可以吗?,c#,dependency-injection,autofac,add-in,C#,Dependency Injection,Autofac,Add In,我正在尝试将DI(with)引入到现有的Windows窗体应用程序中 这个应用程序有一个基本的插件体系结构,每个插件都显示自己的表单。启动时,应用程序扫描已注册的程序集,查找实现IPlugin的类型,然后使用Activator.CreateInstance激活这些类型: public interface IPlugin { Form MainForm { get; } } 我不能改变这个给定的框架。这意味着,每个插件类都是通过非DI方式实例化的,在我看来,我必须为每个插件引导一个单独的

我正在尝试将DI(with)引入到现有的Windows窗体应用程序中

这个应用程序有一个基本的插件体系结构,每个插件都显示自己的表单。启动时,应用程序扫描已注册的程序集,查找实现
IPlugin
的类型,然后使用
Activator.CreateInstance
激活这些类型:

public interface IPlugin
{
    Form MainForm { get; }
}
我不能改变这个给定的框架。这意味着,每个插件类都是通过非DI方式实例化的,在我看来,我必须为每个插件引导一个单独的DI容器

我的问题是,为每个插件创建一个单独的
ContainerBuilder
和容器可以并且仍然合理有效吗?(将有大约10个不同的插件。)或者整个应用程序应该只有一个DI容器吗

下面我提供了我当前解决方案的一些示例代码


使用Autofac;
使用System.Windows.Forms;
公共类插件:IPlugin//由Activator实例化
{
公共窗体MainForm{get;private set;}
public Plugin()//插件框架所需的无参数构造函数
{
var builder=new ContainerBuilder();
RegisterModule(新配置());
var container=builder.Build();
MainForm=container.Resolve();
//^首选新的主窗体(…),因为这样,我可以
//容器自动连接依赖项的优点。
}
}
内部类配置:模块
{
受保护的覆盖无效负载(ContainerBuilder builder)
{
builder.RegisterType().SingleInstance();
//…更多特定于插件的注册请点击此处。。。
}
}
内部类MainForm:Form{/*…*/}

我也不确定是否在插件构造函数中创建一个容器,然后简单地忘记它,但让它在后台进行自动连接,这样可以吗?

理想情况下,容器的使用应该遵循(RRR)。我知道您说过不能更改当前Activator.CreateInstance的用法,但了解它的实际用途仍然会有所帮助

如果没有该约束,则应该只有一个容器实例,由父应用程序本身承载。然后可以使用它来编写所有插件。这将使插件能够共享依赖项。这是MEF采取的路线,它也解决了可扩展性场景

现在,既然你不能这么做,你可以做的下一件最好的事情就是按照你的建议为每个插件设置一个容器。在这一点上,它主要成为一个实现细节。在每个插件中,您仍然应该遵循RRR模式

这会是低效的吗?除非你有很多插件并且一直在创建和销毁它们,否则几个不同的容器应该不会有多大关系。然而,与其创建过早的优化,不如进行度量

在这种情况下,您只能通过使容器保持静态来共享容器。然而,这会使事情变得更加复杂,所以除非绝对必要,否则不要走这条路

我也不确定是否在插件构造器中创建一个容器,然后简单地忘记它,但让它在后台进行自动连接,这样可以吗


几个月后再看我自己的问题,我敢说仅仅忘记
容器
是不好的,因为(a)它是
IDisposable
,应该这样对待,(b)一些组件的生命周期与容器的生命周期绑定,因此容器的生命周期应该明确结束;无论是在表单的
Dispose
方法中,还是在触发其
FormClosed
事件时。

感谢您的回复,@Mark。如果我理解正确,我的示例代码已经遵循RRR模式。。。正确的?(除了我不释放容器,因为它至少需要保持根组件
MainForm
的活动状态。我想,实现这一点的理想方法是使插件
IDisposable
并在
Dispose
方法中释放容器。)您的代码中没有任何内容表明您不遵循RRR,但这很难说。在任何情况下,请记住SingleInstance生活方式只定义了容器范围的Singleton。它不是一个真正的单例,因此您不能以这种方式共享主窗体。
using Autofac;
using System.Windows.Forms;

public class Plugin : IPlugin  // instantiated by Activator
{
    public Form MainForm { get; private set; }

    public Plugin()  // parameter-less constructor required by plugin framework
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new Configuration());
        var container = builder.Build();

        MainForm = container.Resolve<MainForm>();
        // ^ preferred to new MainForm(...) because this way, I can take
        //   advantage of having dependencies auto-wired by the container.
    }
}

internal class Configuration : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MainForm>().SingleInstance();
        // ... more plugin-specific registrations go here...
    }
}

internal class MainForm : Form { /* ... */ }