Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 尝试应用良好的依赖项注入实践时遇到的问题_C#_.net_Design Patterns_Dependency Injection - Fatal编程技术网

C# 尝试应用良好的依赖项注入实践时遇到的问题

C# 尝试应用良好的依赖项注入实践时遇到的问题,c#,.net,design-patterns,dependency-injection,C#,.net,Design Patterns,Dependency Injection,我已经在.NET中使用IoC(主要是Unity)和依赖注入有一段时间了,我非常喜欢这种模式,它可以鼓励创建松散耦合的软件类,并且应该更容易隔离以进行测试 我通常尝试坚持的方法是——特别是不注入容器本身,而只使用构造函数注入,这样您就可以从构造函数签名中清楚地看到类的所有依赖项。确实在这里有一个帐户,但我不确定他是否仍然活跃 不管怎么说,当我最终违反了其他法律之一,或者最终得到了一些感觉不对劲或看起来不对劲的东西时,我不得不质疑我是否遗漏了一些东西,是否可以做得更好,或者干脆不应该在某些情况下使用

我已经在.NET中使用IoC(主要是Unity)和依赖注入有一段时间了,我非常喜欢这种模式,它可以鼓励创建松散耦合的软件类,并且应该更容易隔离以进行测试

我通常尝试坚持的方法是——特别是不注入容器本身,而只使用构造函数注入,这样您就可以从构造函数签名中清楚地看到类的所有依赖项。确实在这里有一个帐户,但我不确定他是否仍然活跃

不管怎么说,当我最终违反了其他法律之一,或者最终得到了一些感觉不对劲或看起来不对劲的东西时,我不得不质疑我是否遗漏了一些东西,是否可以做得更好,或者干脆不应该在某些情况下使用国际奥委会。考虑到这一点,这里有一些例子,如果您能提供一些建议或进一步讨论,我将不胜感激:

  • 具有太多依赖项的类。(“任何具有3个以上依赖项的类都应该被询问是否存在SRP冲突”)。我知道这一点在依赖注入问题中经常出现,但读完这些问题后,我仍然没有任何解决问题的灵丹妙药:

    • a) 在一个大型应用程序中,我总是发现我需要3个依赖项来访问基础设施(例如日志记录、配置、持久性),然后才能获得类完成其(希望是单一职责)工作所需的特定依赖项。我知道有一种方法可以将这些依赖项组重构并打包成一个独立的依赖项组,但我经常发现这只是其他几个服务的一个门面,而不是自己承担任何真正的责任。在本规则的上下文中,是否可以忽略某些基础结构依赖项,前提是类仍被视为具有单一责任

    • b) 重构会加剧这个问题。考虑一个非常普通的任务,就是打破一个有点大的类——你把一个功能区移到一个新的类中,第一个类就依赖于它。假设第一个类仍然需要它以前拥有的所有依赖项,那么它现在有一个额外的依赖项。在这种情况下,我可能不介意这个依赖关系更紧密地耦合,但让容器提供它(与使用new…())相比)更整洁,即使新依赖关系没有自己的接口,它也可以这样做

    • c) 在一个特定的示例中,我有一个类负责每隔几分钟在系统中运行各种不同的函数。由于所有函数都正确地属于不同的区域,所以这个类最终有许多依赖项,以便能够执行每个函数。我猜在这种情况下,应该考虑其他方法,可能涉及事件,但到目前为止,我还没有尝试这样做,因为我想协调任务运行的顺序,在某些情况下,应用逻辑,包括过程中的结果

  • 一旦我在一个应用程序中使用了IoC,我创建的几乎每个被另一个类使用的类都会在容器中注册和/或被容器注入。这是预期的结果还是有些课程与国际奥委会无关?另一种选择是在代码中添加一些新的东西,这看起来就像是一种代码味道,因为它是紧密耦合的。这也和上面的1b有关

  • 我在应用程序启动时完成了所有容器初始化,为系统中的每个接口注册了类型。有些是故意的单实例生命周期,而另一些则可以在每次解析时成为新实例。但是,由于后者是前者的依赖项,因此在实践中它们也成为单个实例,因为它们只在单个实例的构建时解决一次。在许多情况下,这并不重要,但在某些情况下,每次执行操作时,我确实需要一个不同的实例,因此我不能使用内置的容器功能,而是被迫使用I)具有工厂依赖性,这样我就可以强制执行此行为,或者ii)传入容器,这样每次都可以解决问题。在尼古拉的指导下,这两种方法都是不受欢迎的,但我认为我)是两种邪恶中较小的一种,并且在某些情况下我确实使用了它


  • 让我回答问题3。让单例依赖于瞬态是容器探查器试图检测和警告的问题。服务应该只依赖于生命周期大于或等于其自身生命周期的其他服务。注入工厂接口或委托来解决这个问题通常是一个好的解决方案,而传入容器本身则是一个坏的解决方案,因为您最终得到的是

    您可以通过实现代理来解决这个问题,而不是注入工厂。下面是一个例子:

    public interface ITransientDependency
    {
        void SomeAction();
    }
    
    public class Implementation : ITransientDependency
    {
        public SomeAction() { ... }
    }
    
    使用此定义,可以基于
    ITransientDependency
    在中定义代理类:

    public class TransientDependencyProxy<T> : ITransientDependency
        where T : ITransientDependency
    {
        private readonly UnityContainer container;
    
        public TransientDependencyProxy(UnityContainer container)
        {
            this.container = container;
        }
    
        public SomeAction()
        {
            this.container.Resolve<T>().SomeAction();
        }
    }
    
    公共类TransientDependencyProxy:ITransientDependency
    其中T:ITransientDependency
    {
    私有只读UnityContainer容器;
    公共临时依赖CyProxy(UnityContainer容器)
    {
    this.container=容器;
    }
    公共行动
    {
    this.container.Resolve().SomeAction();
    }
    }
    
    现在,您可以将此
    TransientDependencyProxy
    注册为singleton:

    container.RegisterType<ITransientDependency,
        TransientDependencyProxy<Implementation>>(
            new ContainerControlledLifetimeManager());
    
    container.RegisterType(
    新的ContainerControlled LifetimeManager());
    
    虽然它注册为singleton,但它仍将作为瞬态,因为它将把调用转发给瞬态实现

    通过这种方式,您可以完全隐藏
    ITransientDependency
    需要是应用程序其余部分的瞬态

    如果许多不同的服务类型都需要这种行为,那么定义p将变得很麻烦