依赖注入 - 几个类方法中需要的新实例

Chr*_*sCa 29 c# dependency-injection inversion-of-control

我有一些看起来像这样的代码:

public MyService(IDependency dependency)
{
    _dependency = dependency;
}

public Message Method1()
{
    _dependency.DoSomething();

}

public Message Method2()
{
    _dependency.DoSomething();  
}

public Message Method2()
{
    _dependency.DoSomething();  
}
Run Code Online (Sandbox Code Playgroud)

现在我刚刚意识到,因为依赖对象包含内部状态信息.我需要在每个方法调用中新建一个新实例

那么最好的方法是什么,仍然没有新的具体实例?

您是否会使用IoC容器并在每个方法中调用容器?或者是否有一种更流畅的方式,您只能拨打一个容器?

如果我没有使用IoC容器怎么办?是否有办法不在每个方法中新建一个具体实例?

Mar*_*ann 37

到目前为止,大多数答案都建议您将注入的依赖类型更改为某种抽象工厂(Func<T>也是一个抽象工厂)来解决该问题.但是,如果你这样做,那将是一个漏洞抽象,因为你会让特定实现知识决定消费者的设计.这违反了Liskov替代原则.

更好的选择是保持MyService不变,然后为IDependency创建一个解决特定生命周期问题的包装器:

public class TransientDependencyWrapper : IDependency
{
    public void DoSomething()
    {
        new MyStatefulDependency().DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

将其注入MyService而不是直接注入原始实现(MyStatefulDependency).

如果要抽象出依赖项的创建,可以始终在此级别注入抽象工厂.


Jon*_*eet 9

听起来你应该注射供应商/工厂.你如何表示这取决于你(以及你的IoC支持) - 它可以像下面这样简单:

public MyService(Func<IDependency> dependencyProvider)
{
    this.dependencyProvider = dependencyProvider;
}

public Message Method1()
{
    IDependency dependency = dependencyProvider();
    dependency.DoSomething();    
}
Run Code Online (Sandbox Code Playgroud)

...或者您可以拥有此特定工厂类型的接口,或通用IFactory<T>等.有各种可能性 - 但核心位是您注入所需的东西,在这种情况下是"创建一个IDependency每次通话的新实施".

  • @Steven:我不明白为什么.这是一个代表,您可以在需要获取值时调用它.如何使用IProvider <T>`或者其他什么使代码更容易理解? (4认同)
  • 请不要为此使用 `Func&lt;T&gt;`。这使得你的代码很难遵循。 (2认同)

Rex*_*x M 5

如果你需要创建一个注入类型的多个实例,你应该注入一个IDependencyFactory负责控制实例生命周期的实例:

interface IDependencyFactory
{
    IDependency GetInstance();
}
Run Code Online (Sandbox Code Playgroud)

  • @Rex M:另一方面,如果您只需要"创建一个实例",这正是为什么`Func <T>`可以比新界面更具可读性.如果我看到`Func <T>`,我就知道我能用它做什么:调用它来创建一个新实例.我知道周围不会有"新的,疯狂的要求".如果你真的需要一些更复杂的东西,肯定,界面会给你更多的力量 - 但如果你只需要一个行为,为什么不使用委托呢? (3认同)
  • @Steven我通常不能敲@Jon Skeet,但在这种情况下,我总是很高兴我使用了接口,很少我使用了委托.更容易隐藏界面背后的疯狂,意外需求. (2认同)
  • @Steven:它不需要总是创建一个新的T,但接口也没有,除非你把它记录为绝对要求.我确实认为我之前的措辞太快而且松散,但我仍然认为`Func <T>`在很多这种情况下都是一个非常好的类型.不是全部,而是很多. (2认同)