9

我正在尝试将 DI(使用Autofac)引入现有的 Windows 窗体应用程序。

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

public interface IPlugin
{
    Form MainForm { get; }
}

无法改变这个给定的框架。这意味着,每个插件类都是通过非 DI 方式实例化的,在我看来,因此我必须为每个插件引导一个单独的 DI 容器。

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

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


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 { /* ... */ }

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

4

2 回答 2

7

理想情况下,您的容器使用应遵循注册解析发布模式(RRR)。我知道您说过您不能更改当前的 Activator.CreateInstance 用法,但了解它的真正用途仍然会有所帮助。

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

现在,由于您不能这样做,您可以做的下一个最好的事情是按照您的建议为每个插件创建一个容器。那时它主要成为实现细节。在每个插件中,您仍应遵循 RRR 模式。

会不会低效?除非您有很多插件并且一直创建和销毁它们,否则几个不同的容器应该无关紧要。但是,测量比创建过早的优化更好。

在这种情况下,您只能通过将其设为静态来共享容器。然而,这使得事情变得比他们需要的更复杂,所以除非绝对必要,否则不要走那条路。

于 2010-10-15T11:42:27.340 回答
1

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

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

于 2012-02-05T20:15:25.737 回答