【问题标题】:Which IoC containers support returning specific objects based on identifiers?哪些 IoC 容器支持基于标识符返回特定对象?
【发布时间】:2011-06-25 17:15:18
【问题描述】:

我刚刚开始尝试使用 IoC 容器。目前,我正在使用本土工厂来构建我的 ViewModel,它有两种风格:单例和基于 id。换句话说,我的应用程序(根据定义)一次只有一个 Room,因此只有一个 RoomViewModel,但很多用户可以在那个房间里,所以我需要很多 UserViewModel。但我想确保,例如,对于 UserId="johnsmith" 的用户,只创建了一个 UserViewModel,并且任何检索该 UserViewModel 的尝试都将返回相同的实例。

我不知道这是否有助于解释或混淆它们,但这是我目前使用的方法:

public ViewModelType GetViewModelByKey<ViewModelType, KeyType>(KeyType key) 
        where ViewModelType : AlantaViewModelBase, new()
    {
        IDictionary dictionary;
        var type = typeof(ViewModelType);
        if (!keyedViewModelDictionaries.TryGetValue(type, out dictionary))
        {
            dictionary = new Dictionary<KeyType, ViewModelType>();
            keyedViewModelDictionaries.Add(type, dictionary);
        }
        var viewModels = (Dictionary<KeyType, ViewModelType>)dictionary;
        ViewModelType vm;
        if (!viewModels.TryGetValue(key, out vm))
        {
            vm = new ViewModelType();
            viewModels.Add(key, vm);
            vm.Initialize(this);
        }
        return vm;
    }

这意味着这两个调用将返回不同的实例:

// Get VM for user.UserId="john";
var userVM1 = viewModelFactory.GetViewModelByKey<UserViewModel, string>("john");
// Get VM for user.UserId="suzie";
var userVM2 = viewModelFactory.GetViewModelByKey<UserViewModel, string>("suzie");

但是这些将返回相同的实例:

// Get the same VM for user.UserId="bob";
var userVM1 = viewModelFactory.GetViewModelByKey<UserViewModel, string>("bob");
var userVM2 = viewModelFactory.GetViewModelByKey<UserViewModel, string>("bob");

这样做的能力解决了很多数据绑定和同步问题,所以我不会轻易放弃这种模式。

但如果可能的话,我希望迁移到标准 IoC 容器,因为大概它们具有更多功能,不需要特定类型,并且肯定更加标准化。但是在阅读它们时,我没有发现任何明显的迹象表明它们支持我的第二种方法。换句话说,它们都支持标准的两种生活方式(单例和瞬态),但我想要一些不同的东西:每个对象身份的单例。标准 IoC 容器是否支持这一点?如何?哪些?

抱歉,这是一个基本问题。

【问题讨论】:

    标签: c# mvvm ioc-container


    【解决方案1】:

    MEF 通过Export 使用“合同名称”支持这一点。这允许您使用指定的合同名称导出和导入:

    [Import("bob", typeof(UserViewModel)]
    public UserViewModel bobViewModel { get; set; }
    

    由肯·史密斯编辑
    请参阅下面的讨论,了解我们的最终结论,即 IoC 容器不支持这种开箱即用的行为,并且可能并不是真正为解决这个问题而设计的。

    【讨论】:

    • 这是否允许我指定 在运行时 我希望此 UserViewModel 用于“Bob”(而不是在设计时)?到目前为止,我在 MEF 导出/导入属性的文档中读到的任何内容都没有让我相信这一点,但我很可能是错的。
    • “Bob”和“Fred”的区别在于他们是不同的用户。换句话说,Web 服务将在不同的点返回许多不同的用户对象实例,一些具有 UserId="Bob",一些具有 UserId="John",等等。我需要用 UserViewModel 包装这些用户对象,但我只想为每个用户创建一个 UserViewModel,即使(在不同时间)Web 服务可能会为同一个(真实世界)用户返回不同的 User 对象。这有意义吗?
    • @Ken:有点——就个人而言,在用户周围包装一个新的虚拟机可能比尝试以这种方式解决这个问题要容易得多。否则,我只需导入一个工厂来创建您的 VM,然后自己将结果存储在字典中。
    • 问题是我有一堆东西(事件处理程序、数据绑定等)已经连接到现有的 VM。因此,如果更新的模型来自(双工)Web 服务,如果我可以只更新现有 VM 的模型属性而不创建新实例,它就解决了很多问题。我现在正在做字典词典的事情(如您在上面的代码示例中所见),我只是想知道这是否是 IoC 容器应该解决的问题。开始听起来好像不是。
    • @Ken:是的,IoC 容器并不是真正针对这个问题,而是针对可发现性和类型。他们擅长插入需求,但不管理普通类型的生命周期,尤其是。单一类型的多个实例,这就是您所描述的。
    【解决方案2】:

    Spring.NET 当然支持非单例命名对象。 Singleton 是默认的 DI 行为,但您也可以指定创建单个实例。

    请参阅文档here

    【讨论】:

    • 我猜你说的是“原型”范围?如果是这样,我认为这不是我正在寻找的东西,除非文档中有我刚刚丢失的东西。我特别不希望每次调用context.GetObject("UserViewModel") 时都创建一个新实例。我想的语法更像context.GetObject&lt;UserViewModel&gt;(uvm =&gt; uvm.UserId = 'Bob')
    • 啊——那是我的错。我不知道 Spring.NET 中的这种内置功能 - 您必须编写自己的数据结构或自己的对象范围(egads)。
    猜你喜欢
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    相关资源
    最近更新 更多