【问题标题】:Creating objects using Unity Resolve with extra parameters使用带有额外参数的 Unity Resolve 创建对象
【发布时间】:2009-10-02 13:16:17
【问题描述】:

我正在使用 Prism,它也是一个不错的 Unity IoC 容器。我是这个概念的新手,所以我还没有完全掌握它。我现在要做的是使用 IoC 容器创建一个对象,但也传递一个额外的参数。请允许我用一个例子来解释..:

我有一个接受命令对象的类。这是在 IoC 容器中注册的,所以它会很好地处理它:

public class Person 
{
    public Person(IApplicationCommands commands) { .. }
    ..
}

Person person = _container.Resolve<Person>();

现在 - 我想传入另一个参数 - 例如该人的姓名。但是,我仍然想使用 IoC 容器来处理解析,从而从 IoC 容器中获取其他参数。但是将名称作为“自定义”参数传入。这个可以吗?

public class Person 
{
    public Person(IApplicationCommands commands, string name) { .. }
    ..
}

string name = "John"; 
Person person = _container.Resolve<Person>(name); // ....?? 

这个例子似乎不起作用,但有没有办法让它起作用?或者 Unity IoC 容器是否需要在调用 Resolve 之前在容器中注册所有参数?

【问题讨论】:

    标签: c# .net unity-container prism


    【解决方案1】:

    Can I pass constructor parameters to Unity's Resolve() method?

    container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
    

    【讨论】:

    • 嘿!非常好!我没有看到这个,但它类似于 Ninject 最近添加的内容。我得拉下最新版本,看起来像。谢谢!
    • 如果在构造函数中更改参数名称会怎样?
    • 很好的答案!我一直在寻找答案几个小时。
    【解决方案2】:

    编辑:在我看来,这个答案已经过时了,因为它假设了旧版本的 Unity。 NotDan's answer 更好。


    您有几个选择。老实说,它们有点蹩脚,但它们会起作用。

    选项 1:作用域容器

    如果你想使用构造函数 注入,你需要创建一个 范围容器并放置您的数据 进入那个作用域容器:

    IUnityContainer subContainer = _container.CreateChildContainer();
    
    //Don't do this... create a custom type other than string, like
    // MyConstructorParams or something like that... this gets the point across.
    subContainer.RegisterInstance<string>("John");
    Person person = subContainer.Resolve<Person>();
    

    选项 2:初始化方法

    不过,我通常做的是 在我的单独初始化方法 实例变量的目标对象:

    public class Person
    {
         public Person(IApplicationCommands commands)
         { .. }
         public void Initialize(string name) { .. }
    
         ..
    }
    

    然后你的用法变成:

    Person person = container.Resolve<Person>();
    person.Initialize("John");
    

    两者都不是特别令人愉快,但它会完成工作。重要的是要选择一个约定并坚持下去,否则你会迷失方向。

    希望这会有所帮助。

    【讨论】:

    • 我不会推荐这两种方法。虽然使用范围容器或注册逻辑命名的实例对于某些场景肯定是有效的技术,但考虑到创建新 DDD 实体的假定上下文,它们并不合适。如果这与新客户注册相关联,您当然无法预测可能需要创建哪些新 Person 对象,即使您可以……嗯,我想您理解会出现的问题。第二种选择当然更可行,但最好通过构造函数参数来表达所需的依赖关系......
    • 这也没有解决我认为的 Person 建模的缺陷,以及直接使用容器作为服务定位器来创建这种类型。
    • 当然,范围容器选项是这两个选项中最愚蠢的选项,但它确实有效。我还假设 OP 简化了他的问题,他并没有试图在一个简单的实体上做这样的事情,而是一个更复杂的服务对象。对于这些对象,我一直有这个问题,其中对象具有一些依赖关系,但还需要传递给它的一些实例数据,当它被传递时我需要对其采取行动。这就是为什么其他 IoC 容器,如 Ninject,完全支持 OP 想要的。 Unity 还没有。
    • 感谢您的反馈。是的@Imes - 我当然把这个问题弄傻了..
    • 我很抱歉。出于某种原因,我假设您的字符串“John”的子容器注册发生在应用程序启动时,这就是我认为它不切实际的原因。你是对的,这是一个可行的解决方案,但我仍然建议不要在这种情况下使用任何容器作为服务定位器。
    【解决方案3】:

    您可以考虑以下几种选择:

    如果您需要创建一个除了提供的任何数据(例如客户名称)之外还具有 合法 依赖关系的新实体,请将其封装到一个工厂中,该工厂本身已被注入调用对象:

    Person person = _personFactory.CreatePerson("bubba");
    

    工厂可以注入实体的依赖项,并在需要时提供给构造函数,如果可选,可以通过其他方式设置:

    var person = new Person("bubba", _domainService);
    

    对于瞬态变量依赖,例如特定方法使用的策略,使用Double Dispatch:

    public class Person
    {
        public void DoSomethingWith(SomeStrategy strategy)
        {
            strategy.DoSomething(this);
        }
     }
    

    【讨论】:

    • 这仅在您假设 Person 只是一个简单实体时才成立,这在这种情况下是有效的,但并不能解决 Unity 在所有情况下的这个缺点。 Ninject 和其他一些 IoC 容器能够完全按照 OP 的要求执行操作,但 Unity 没有,这给我们留下了一些非常有限的选择。我同意作用域容器是有史以来最糟糕的事情(我个人不这样做),但它是一个解决方案。
    • Person 只是一个虚构的类来简化这个问题。在我的场景中,我不是针对域类执行此操作,而是针对域类的 ViewModel 表示。我正在使用 Prism,在这种情况下,“人”视图必须触发命令以显示某些区域中的一些子数据,为此我需要 IApplicationCommands。
    • @Anderson Imes:我不知道某些容器启用了此功能。我可以想象在某些情况下这可能有用,但总的来说,我仍然推荐使用工厂或双重调度方法而不是使用容器作为服务定位器,因为这些方法保留了对基础设施的无知。至少,您可以通过在工厂中封装容器特定技术来限制代码对直接调用容器的依赖。
    • 我 100% 同意您的所有观点。我提供范围容器解决方案只是因为它允许 Unity 像 Ninject 等其他容器一样工作。第二种解决方案旨在完全替代使用容器(这是我在使用 Unity 而不是 Ninject 的项目中所做的)。
    • 经过一段时间和一些经验后重新审视这一点(令人惊讶的是,事情在 2 年内发生了怎样的变化),我现在相信这是最佳答案。它减少了需要容器本身知识的表面积,并使测试变得更加容易(模拟其中一些 Unity 解析方法很棘手)。先生,您正前往投票城市。
    【解决方案4】:

    我想不出任何方法可以通过构造函数注入来做到这一点。我认为您需要对依赖项使用property injection(标有 Dependency 属性),然后仅在构造函数中获取字符串,实例化自己,然后使用BuildUp 连接依赖项,或者使字符串成为属性也是你在 Resolve 之后手动设置的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 2020-10-12
      • 2012-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      相关资源
      最近更新 更多