Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.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#_Asp.net Mvc_Dependency Injection_Structuremap_Recommendation Engine - Fatal编程技术网

C# 没有构造函数的依赖注入:真的是一种糟糕的做法吗?

C# 没有构造函数的依赖注入:真的是一种糟糕的做法吗?,c#,asp.net-mvc,dependency-injection,structuremap,recommendation-engine,C#,Asp.net Mvc,Dependency Injection,Structuremap,Recommendation Engine,我正在使用C#、MVC4、StructureMap等的web解决方案 在解决方案中,我为控制器提供了服务。举例来说: public class ServiceA{ private readonly IRepository _repository1; private readonly IRepository _repository2; public ServiceA(IRepository1 repository1, IRepository2 repository2){

我正在使用C#、MVC4、StructureMap等的web解决方案

在解决方案中,我为控制器提供了服务。举例来说:

public class ServiceA{
    private readonly IRepository _repository1;
    private readonly IRepository _repository2;

    public ServiceA(IRepository1 repository1, IRepository2 repository2){
        _repository1=repository1;
        _repository2=repository2;
    }

    public void DoSomethingA(){
        _repository1.DoSomething();
    }

    public void DoSomethingB(){
        _repository2.DoSomething();
    }
}

public class ServiceB{
    private readonly IRepository _repository3;
    private readonly IRepository _repository4;

    public ServiceB(IRepository3 repository3, IRepository4 repository4){
        _repository3=repository3;
        _repository4=repository4;
    }

    public void DoSomethingA(){
        _repository3.DoSomething();
    }

    public void DoSomethingB(){
        _repository4.DoSomething();
    }
}
这样做是一种良好的做法:

public abstract class ServiceBase(){
    public IRepository1 Repository1 { get { return instanceOf<IRepository1>(); }}
    public IRepository2 Repository2 { get { return instanceOf<IRepository2>(); }}
    public IRepository3 Repository3 { get { return instanceOf<IRepository3>(); }}
    public IRepository4 Repository4 { get { return instanceOf<IRepository4>(); }}

    private T instanceOf<T>()
    {
        return ServiceLocator.Current.GetInstance<T>();
    }
}
通过第二种选择,我看到了某些优势:

  • 没有必要为每个存储库都设置一个私有变量
  • 我不需要服务的构造函数,使它们更小、更易于阅读
  • 所有存储库都可以在任何服务中使用
  • 该服务不会得到不必要的实例。例如,调用
    ServiceA
    方法
    DoSomethingA
    服务定位器
    get only
    Repository1
    实例。(使用第一种方法将收到两个实例:for
    Repository1
    Repository2
在这两种情况下,我都可以进行适当的测试:

  • 在第一种情况下,通过构造函数发送模拟对象
  • 在第二种情况下,配置StructureMap以在必要时使用模拟对象

你认为呢?我违背了一些原则?(对不起,我的英文版)

我看到这种设计的问题是,您将ServiceLocator与服务紧密耦合,因此不提倡松散耦合。如果要使用模拟/测试存储库对服务进行单元测试,会发生什么?或者甚至交换DI实现。实际上,这可能不是什么大问题,因为您可以通过服务定位器配置测试服务,但我觉得代码有点臭

让我们先看看优势参数:

没有必要为每个存储库都设置一个私有变量

没错。虽然在现实中,这4个字节作为参考通常并不重要

我不需要服务的构造器,使它们更小、更安全 更容易阅读

我的看法正好相反。拥有构造函数会立即告诉您类具有哪些依赖项。对于基类,您必须查看整个类才能获得这些信息。此外,如果您有一个低耦合、高内聚和无纠结的良好设计,则无法使用工具进行分析。而那些使用该类的人根本不知道该类有什么依赖关系,除非他们阅读了实现

所有存储库都可以在任何服务中使用

应该避免在一个服务中使用多个repo,因为这会增加耦合。向所有服务提供所有回购协议是鼓励高耦合的糟糕设计的最佳方式。所以我认为这是一个缺点

该服务不会得到不必要的实例。举个例子,打电话进来 ServiceA方法DoSomethingA ServiceLocator仅获取 Repository1实例。(使用第一种方法将收到两个 实例:用于Repository1和Repository2)

一个使用完全不同的依赖关系和不同方法的服务是一个巨大的迹象,表明它没有遵循标准。在这种情况下,它很可能会被分成两个服务

关于可测试性:在第二种情况下,通过使用单例(ServiceLocator),您的测试不再是孤立的。所以他们可以互相影响。尤其是在并行运行时


我认为你走错了路。使用时,您向使用您的类的人隐藏了依赖关系,这使得阅读实现的人更难看到该类具有哪些依赖关系,并且您的测试不再是孤立的。

谢谢您!你的几行评论节省了我很多时间和头疼!你的意见和一个朋友给我的完全一样,只是想在这里问一下,因为我不太了解缺点。现在我看得更清楚了。非常感谢您抽出时间。您好。@remo gloor+1获取详细答案,但当您需要
暂时性
依赖关系时,例如,如果服务需要像
AWS S3
或类似的远程存储,则性能会出现一个问题。这将不必要地为所有控制器创建/处置实例,即使它们可能不会在单个请求范围内被调用。使用
Get()
并用属性修饰类,使其具有该类所需的类型,并且
Get()
将只返回修饰类型的实例。或者公共属性注入,那当然可以利用getter的优势来使用惰性加载。谢谢Ringo!你的答案和Remo的一样,只是有点短,所以我拨的是正确的,但都是正确的。问候语!
public class ServiceA : ServiceBase
{
    public void DoSomethingA(){
        Repository1.DoSomething();
    }

    public void DoSomethingB(){
        Repository2.DoSomething();
    }
}


public class ServiceB : ServiceBase
{
    public void DoSomethingA(){
        Repository3.DoSomething();
    }
    public void DoSomethingB(){
        Repository4.DoSomething();
    }
}