【问题标题】:Can't Inject dependency for List<t> as constructor argument using Unity无法使用 Unity 将 List<t> 的依赖项作为构造函数参数注入
【发布时间】:2015-05-18 22:25:16
【问题描述】:

我正在使用 Unity 来实例化我的 MenuRepository 实例。尝试这样做时出现以下错误..

类型列表`1 有多个长度为 1 的构造函数。无法消除歧义。

我尝试了以下注册,但没有运气..

container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new InjectionConstructor(typeof(IMonopolyEntitiesDbContext), 
    typeof(List<MenuLink>)));

这是我的注册信息

container.RegisterType<MenuLink>();
container.RegisterType <List<MenuLink>>();
container.RegisterType<IMonopolyEntitiesDbContext, MonopolyEntities>(
    new PerThreadLifetimeManager());
container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new InjectionConstructor(typeof(IMonopolyEntitiesDbContext), typeof(List<MenuLink>)));

MenuRepository

public class MenuRepository : IMenuRepository
{
    IMonopolyEntitiesDbContext _dbContext;
    List<MenuLink> _allsubMenus;

    public MenuRepository(IMonopolyEntitiesDbContext context, List<MenuLink> allsubMenus)
    {
        _dbContext = context;
        _allsubMenus = allsubMenus;
    }
}

【问题讨论】:

  • List 有多个构造函数。 Unity 找不到应该使用哪个……您需要向 unity 提供更多信息。但我建议您创建一个服务来创建列表并将此服务注入您的存储库。
  • 确实如此,Unity 需要知道您的意思是List&lt;T&gt;(sequence) 还是List&lt;T&gt;(length)
  • List&lt;MenuLink&gt; 包含什么?这是在应用程序期间不会更改的MenuItem 对象的固定列表吗?或者是每次请求都从数据库中请求的数据?你能详细说明一下吗?
  • 嗨,阿布,我已经为你写了一个很长的答案。不过我还没有发布它,因为我缺少一些能够回答这个问题的基本信息。如果您能回答我之前关于List&lt;MenuLink&gt; 的问题,我可以发布我的答案并帮助您解决问题。
  • 抱歉回复晚了。 List menuItem 对象的状态在应用程序和单例期间不会改变,但集合可以改变。 MenuItem 对象将保存从数据存储中调用的数据。我现在已经解决了这个问题,很快就会发布我的答案。

标签: c# unity-container


【解决方案1】:

您需要了解 IoC 容器的目标是将抽象映射到实现并从中构建对象图。所以为了能够创建对象,Unity 需要知道如何创建对象。但是,List&lt;T&gt; 不是您的典型服务类型。它有多个构造函数,因此 Unity 不知道如何创建这种类型。

但是即使它确实知道如何创建它(例如通过使用List&lt;T&gt; 的默认构造函数),这对你来说仍然是相当无用的,因为在这种情况下会向消费者注入一个空列表。这根本没用。

因此,您至少应该明确指定要注入的内容。例如通过这样做:

container.RegisterInstance<List<MenuLink>>(new List<MenuLink>
{
    new MenuLink { Id = 1, Name = "foo" },
    new MenuLink { Id = 2, Name = "bar" },
    new MenuLink { Id = 3, Name = "foobar" },
});

这对你有用,因为你说List&lt;MenuLink&gt; 实际上是一个单例并且不是从数据库中填充的。然而,在你的容器中注册这个List&lt;MenuLink&gt; 仍然会有问题,因为这个List&lt;T&gt; 现在可以注入任何消费者,而你不应该这样做。这个List&lt;MenuLink&gt;MenuRepository 的一个实现细节,它可能负责更新它。将List&lt;MenuLink&gt; 注入其他消费者是有风险的,因为List&lt;T&gt; 不是线程安全的。最好将此List&lt;T&gt; 保留在MenuRepository 内部,这样它就可以进行适当的锁定。

因此,不要在容器中注册List&lt;MenuLink&gt;,而是使用列表显式注册存储库,如下所示:

var menuLinks = new List<MenuLink>
{
    new MenuLink { Id = 1, Name = "foo" },
    new MenuLink { Id = 2, Name = "bar" },
    new MenuLink { Id = 3, Name = "foobar" },
};

container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new ParameterOverride("allsubMenus", menuLinks));

【讨论】:

    【解决方案2】:

    我使用了不带参数的 InjectionConstructor。

    using (var c = new UnityContainer())
    {
        c.RegisterType(typeof(List<string>), new InjectionConstructor());
        c.RegisterType<IMyParamClass, MyParamClass>();
    
        c.RegisterType<IMyClass, MyClass>(
                        new PerThreadLifetimeManager(),
                        new InjectionConstructor(typeof(IMyParamClass),
                        typeof(List<string>)));
    
        var obj = c.Resolve<IMyClass>();
        obj.write();
    }
    

    .

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多