在静态构造函数中初始化容器

Initialize container in static constructor

在静态构造函数中初始化简单注入器容器是否合法?

示例:

using SimpleInjector;

public static Bootstrapper
{
    private readonly static Container container;

    static Bootstrapper()
    {
        Bootstrapper.container = new Container();
    }
}

应该没问题,static 构造函数保证在类型首次使用之前只调用一次并且是线程安全的。

来自规范

Static constructors are not inherited, and cannot be called directly. The static constructor for a closed class type executes at most once in a given application domain.

The execution of a static constructor is triggered by the first of the following events to occur within an application domain:
• An instance of the class type is created.
• Any of the static members of the class type are referenced.

根据我的经验,在大多数情况下您应该尽量避免使用静态实例。想象一下,容器 的生命周期与应用程序的生命周期相匹配。换句话说,如果您将 container 设置为静态,它将保持活动状态直到应用程序关闭。

要获得更好的做法,请找到您的应用程序的入口点。假设它是 static void Main()。在这种情况下,在这里创建一个容器的实例,并使用这个容器创建启动对象(Windows、Forms 等)。

如果您正确设计了 DI,您以后在应用程序中应该不需要 container 对象。只需确保在需要时通过构造函数将服务(已注册到 容器)注入到对象中即可。

此外,请查看 Service Locator violates SOLID by Mark Seemann。 Mark 有很多关于 DI 的帖子,并解释了为什么这是一种不好的做法。

正如@NedStoyanov 所说,静态构造函数可以保证唯一性,因此这可能是有益的。然而,静态构造函数的缺点是它们通常更难调试,并且从 cctor 主体抛出的任何异常都包含在 InitializationException 中,这使得更难看到实际问题。

我还想重复@WSriramSakthivel 的警告:尽管在组合根中将 Container 声明为 public readonly static 字段,但请防止从 外部 [=22= 访问此字段] 组合根,只要有可能。从组合根外部使用它意味着应用 Service Locator anti-pattern.

请注意,使用 cctor 初始化容器也有缺点。在集成测试和 运行 一些使用容器构建对象图的集成测试中验证容器时,您通常希望让每个测试都有自己的容器实例,其配置略有不同。这是你在使用 cctor 时无法工作的东西。

长话短说,虽然使用 cctor 可能很好并且提供了一些很好的保证,但我认为在大多数情况下,它只会成为阻碍。