【问题标题】:Which lifetime manager to use to create new instances in foreach loops using Unity使用 Unity 在 foreach 循环中创建新实例的生命周期管理器
【发布时间】:2019-01-22 04:00:47
【问题描述】:

我有一个示例,我想使用 DI 在 foreach 循环中创建类的实例,但无法确定要使用哪个生命周期管理器。默认生命周期管理器显然只会使用注入到控制器中的实例,每次调用实例时我都想在其中创建新实例,如下例所示。我正在使用 Microsoft Unity

简单的接口类

public interface ISomeClass 
{
    string GetValue(string value);
}

public class SomeClass : ISomeClass
{
    public string GetValue(string value) 
    {
        return value;
    }
}

在容器中注册

container.RegisterType<ISomeClass, SomeClass>(new TransientLifetimeManager());

实施

private readonly SomeClass _someClass;

public MyController(SomeClass someClass)
{
    _someClass = someClass;
}

// someStringList would contain values like "hello", "world", "o", "hai"
public void Whatever(List<string> someStringList) 
{
    List<string> otherStringList = new List<string>();

    foreach (var someString in someStringList)
    {
        // _someClass.GetValue will simply return the same value
        otherStringList.Add(_someClass.GetValue(someString));
    }

    // otherStringList contain as many elements as the someStringList 
    // but all will be the same as the last element in the list
}

【问题讨论】:

  • 第一件事,你为什么要插入具体类型而不是界面?一种可能的解决方案是创建工厂接口并在 for 循环中创建新实例...
  • @Johnny 是的,我可以看到我的示例有点混乱

标签: c# dependency-injection unity-container


【解决方案1】:

TransientLifetimeManager 终身管理器是必经之路。每次您或容器本身调用 Resolve 时,该对象都会创建新对象。


所以重点是在foreach 中以某种方式启动Resolve。天真\简单的方法可能是将IUnityContainer 本身注入您的控制器,IUnitContainer 本身始终可用...

private readonly IUnityContainer _container;

public MyController(IUnityContainer container)
{
    _container = container;
}

然后手动解析ISomeClass

foreach (var someString in someStringList)
{
     var someClass = _container.Resolve<ISomeClass>();
     otherStringList.Add(_someClass.GetValue(someString));
}

一般来说,我更喜欢某种工厂或原型模式,而不是注入 IUnityContainer 本身,因为这可能被认为是一种不好的做法。容器应该更多地用作隐形助手而不是一等公民......

简单工厂方法可以是注册简单工厂方法:

_container.RegisterType<Func<ISomeClass>>(new InjectionFactory(_ => 
            new Func<ISomeClass> (() => _container.Resolve<ISomeClass>())));

然后你可以将它注入你的控制器:

private readonly Func<ISomeClass> _factory;

public MyController(Func<ISomeClass> factory)
{
    _factory = factory;
}

然后你就是:

foreach (var someString in someStringList)
{
     ISomeClass someClass = _factory();
     otherStringList.Add(_someClass.GetValue(someString));
}

第二种方法的好处是你有显式依赖而不是注入 IoC,这让你的设计更简洁。

【讨论】:

  • 第二个例子就像你说的那样更干净,用_container.Resolve&lt;SomeClass&gt;()替换_container.Resolve&lt;ISomeClass&gt;()使它工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 2010-09-07
  • 1970-01-01
  • 2010-10-16
  • 2011-09-15
  • 2020-09-20
相关资源
最近更新 更多