C# IoC实例化可能的最新时间

C# IoC实例化可能的最新时间,c#,inversion-of-control,ioc-container,simple-injector,C#,Inversion Of Control,Ioc Container,Simple Injector,在我的应用程序中,我使用以下模式提供了许多服务: 在与接口相同的文件中,我定义了一个由IoC容器控制的静态工厂方法,如下所示: public interface ISomethingService { Task DoSomethingAsync(int id); } public class SomethingServicFactory : ServiceFactory<ISomethingService > { } public class ServiceFactory

在我的应用程序中,我使用以下模式提供了许多服务: 在与接口相同的文件中,我定义了一个由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();
}
这允许我将创建延迟到最后一刻,但仍然可以使用容器控制服务创建。我刚开始使用SimpleInjector。 更重要的是,它允许我创建一个服务实例,并在向IoC提供控制的同时轻松地传递它的参数

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


我担心使用此模式会遗漏一个重要的设计/架构问题,我正在寻找国际奥委会专家对此模式的评论。

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

  • :您的
    CreateClosure
    属性强制您在创建服务工厂后初始化服务工厂。当您忘记这一点时,应用程序将在运行时失败。时间耦合是一种代码气味
  • :CreateClosure充当环境上下文(与Singleton设计模式非常相似,但能够使用静态方法或属性更改值)。这会导致隐藏类的依赖项,而不是使用类的构造函数“静态声明”。我们认为环境上下文是反模式(参见第5章)。
  • 违反:您的工厂是具体的类,而DIP促进了与接口的对话。因此,您的代码变得强耦合,难以测试
  • :当应用依赖项注入时,工厂的用处就消失了。尤其是对于应用程序中的每个抽象都有一个工厂的想法是绝对不允许的
相反,使用依赖项注入,一切都变得容易得多:当我们应用构造函数注入时,我们可以简单地将
ISomethingService
注入到它的消费者中。这:

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

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

  • :您的
    CreateClosure
    属性强制您在创建服务工厂后初始化服务工厂。当您忘记这一点时,应用程序将在运行时失败。时间耦合是一种代码气味
  • :CreateClosure充当环境上下文(与Singleton设计模式非常相似,但能够使用静态方法或属性更改值)。这会导致隐藏类的依赖项,而不是使用类的构造函数“静态声明”。我们认为环境上下文是反模式(参见第5章)。
  • 违反:您的工厂是具体的类,而DIP促进了与接口的对话。因此,您的代码变得强耦合,难以测试
  • :当应用依赖项注入时,工厂的用处就消失了。尤其是对于应用程序中的每个抽象都有一个工厂的想法是绝对不允许的
相反,使用依赖项注入,一切都变得容易得多:当我们应用构造函数注入时,我们可以简单地将
ISomethingService
注入到它的消费者中。这:

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

这听起来很像
懒惰
这听起来很像
懒惰
SomethingServicFactory .CreateClosure = () => 
    Container.GetInstance<ISomethingService >();
var somethingService= new SomethingService().GetDefault();