关于c#:通过构造函数在IoC中实现依赖关系?

Enforcing dependencies in IoC via a constructor?

我试图在使用IOC/Dependency注入的同时将编程收缩,而不是特定的类。我面临的困境是:

  • 为国际奥委会做接口编程:我从一开始就非常依赖接口。从Spring的示例项目来看,在编程与IOC签订合同时,接口是可行的方法。

  • (……尽管抽象类通常更受欢迎:接口的主要缺点是,在允许API进化方面,它们比类要灵活得多)

  • 通过构造函数使类依赖关系显式化我的直觉是,将依赖项传递给类的构造函数是一种很好的编程实践。实际上,这是依赖注入。

  • …但不能在接口/抽象类中强制构造函数签名:接口或抽象类都不允许定义构造函数签名(容易/优雅)。另请参见框架设计指南第4.4节:不要在抽象类型中定义公共或受保护的内部构造函数。…只有当用户需要创建该类型的实例时,构造函数才应该是公共的。

  • 这个问题与前面的stackoverflow问题有关:定义构造函数签名的接口?

    但我的问题是:

    因为您不能在C接口/抽象类中定义构造函数,正如上面的问题所要求的那样,在实际级别上:

    如何将这与通过构造函数传递依赖项的合理实践协调起来?

    编辑:谢谢你的回答。我希望能对我在这件事上应该做些什么有所了解。只是不使用contractor args?使用某种类型的init()方法来获取依赖项?伊迪丝2:谢谢你的回答,非常有帮助。


    我一直认为用一个(虚构的)例子来解释这件事比较容易…

    假设您有一个icustomerepository接口、一个ishoppingcartpository接口和一个icheckout接口。您有这些接口的具体实现——customerrepository、shoppingcartreository和checkoutservice。

    您的checkoutService concrete类有一个构造函数,该构造函数接受ICustomerRepository和IShoppingCartPository,例如

    1
    2
    3
    4
    5
    6
    public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
    {
      // Set fields for use in some methods later...
      _customerRepository = customerRepository;
      _shoppingCartRepository = shoppingCartRepository;
    }

    然后,当您希望ICheckOutService实现完成一些工作时,您可以告诉IOC容器它应该为每个接口类型使用哪个具体类,并要求它为您构建一个ICheckOutService。您的IOC容器将为您构建类,并将正确的具体类注入到您的checkoutService的构造函数中。它还将在这里沿着类继承关系一直构建依赖关系,因此,例如,如果ShoppingCartRepository在构造函数中采用IDatabaseSession接口,则IOC容器也将注入该依赖关系,只要您告诉它要为IDatabaseService使用哪个具体类。

    以下是在将(例如)structuremap配置为IOC容器时可能使用的一些代码(此代码通常在应用程序启动期间调用):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class AppRegistry : Registry
    {
      public AppRegistry()
      {
        ForRequestedType<ICheckoutService>().TheDefaultIsConcreteType<CheckoutService>();
        ForRequestedType<ICustomerRepository>().TheDefaultIsConcreteType<CustomerRepository>();
        // etc...
      }
    }

    然后,为了获得一个已构建并准备好的ICheckOutService实例,并将所有依赖项传递给您的构造函数,您将使用如下内容:

    1
    var checkoutService = ObjectFactory.GetInstance<ICheckoutService>();

    我希望这是有道理的!


    您的IOC容器必须从具体类型构造一个对象,即使您传递的是一个接口。构造函数不是行为或状态协定,因此它不属于接口或抽象类的公共成员。

    构造函数是一个实现细节,因此不需要将其定义与具体类分离。


    不能在接口中定义构造函数签名。这无论如何都没有意义,因为接口不应该强制实现的构造方式。

    不过,抽象类确实可以有构造函数。它们必须受到保护,因为公共构造函数也没有意义。它们只能由具体的子类调用。

    IOC原则规定,不要让类A知道并实例化类B,而是应该将对ib的引用传递给a的构造函数。这样,a就不需要知道类B,因此您可以很容易地用一些其他的ib实现来替换类B。

    因为您传递的是已经实例化的类B对象,所以ib接口不需要有构造函数签名。