【问题标题】:IoC Instantiate latest time possibleIoC 实例化可能的最新时间
【发布时间】:2026-02-15 01:55:01
【问题描述】:

在我的应用程序中,我有许多服务,我使用以下模式: 在与接口相同的文件中,我定义了一个由 IoC 容器控制的静态工厂方法,如下所示:

public interface ISomethingService {
    Task DoSomethingAsync(int id);
}

public class SomethingServicFactory : ServiceFactory<ISomethingService > { }

public class ServiceFactory<T>
{
    public static Func<T> CreateClosure;
    public T GetDefault() => CreateClosure();
}

创建和配置 IoC 容器后:

SomethingServicFactory .CreateClosure = () => 
    Container.GetInstance<ISomethingService >();

稍后在我的应用程序中需要SomethingService 时:

var somethingService= new SomethingService().GetDefault();

这允许我将创建推迟到最后一刻,但仍然可以使用容器控制服务创建。我刚开始使用 SimpleInjector。 更重要的是,它允许我创建服务实例并轻松传递参数,同时将控制权交给 IoC。

这个模式对我有帮助的一个很好的例子是 WPF XAML 实例化的用户控件,它需要填充数据(即从数据库中查找值)。在后面的代码中,我能够轻松地创建 DbContext 并从数据库中获取数据。不过,我也开始在整个应用程序中使用它。

我担心使用此模式会遗漏一个重要的设计/架构问题,我正在寻找 IoC 专家关于此模式的 cmets。

【问题讨论】:

  • 这听起来很像Lazy&lt;T&gt;

标签: c# inversion-of-control ioc-container simple-injector


【解决方案1】:

您的设计暴露了以下代码异味和反模式:

  • Temporal Coupling:您的CreateClosure 属性强制您在创建服务工厂后对其进行初始化。当您忘记这一点时,应用程序将在运行时失败。时间耦合是一种代码味道。
  • Ambient ContextCreateClosure 充当环境上下文(这很像单例设计模式,但能够使用静态方法或属性更改值)。这会导致隐藏类的依赖项,而不是使用类的构造函数“静态声明”。在Dependency Injection in .NET 2nd edition 中,我们认为环境上下文是一种反模式(参见第 5 章)。
  • Dependency Inversion Principle 违规:您的工厂是具体的类,而 DIP 促进与接口的对话。因此,您的代码会变得强耦合且难以测试。
  • Abstract Factories are a code smell:当应用依赖注入时,工厂的用处就消失了。尤其是为应用程序中的每个抽象都建立一个工厂的想法是绝对不行的。

相反,使用依赖注入,一切都变得容易得多:当我们应用构造函数注入时,我们可以简单地将ISomethingService 注入它的消费者。这个:

  • 通过查看构造函数,明确类的依赖关系
  • 允许 DI 容器为您组成对象图并对图进行分析和诊断
  • 允许容器管理对象的生命周期
  • 不再需要工厂(因为容器将扮演该角色)
  • 减少类的依赖数量。不需要 2 个(一个用于工厂,一个用于服务),您只需要一个(用于服务)。

【讨论】: