【问题标题】:Casting a Dictionary<int, List<User>>转换字典<int, List<User>>
【发布时间】:2014-02-20 13:44:17
【问题描述】:

Dictionary&lt;int, List&lt;User&gt;&gt; 转换为Dictionary&lt;int, IEnumerable&lt;User&gt;&gt; 的最有效方法是什么?

这样做的原因是我有一个构建 Dictionary&lt;int, List&lt;User&gt;&gt; 的方法,但我不希望将可变的 List 返回给调用代码。

我是否必须将这本词典投影到新类型中?

【问题讨论】:

  • 字典是否需要将List&lt;User&gt; 作为值?您可以填写List&lt;User&gt; 并将其添加到Dictionary&lt;int, IEnumerable&lt;User&gt;&gt;
  • 如果可以的话,您可以编写一个返回 IEnumerable 的方法,该方法会为调用者查找索引。这样您就不必一次性转换所有内容,而只需根据索引请求进行转换。
  • 将其设为IEnumerable 不会阻止可变性。如果您想保证调用者不能更改底层列表,您需要一个不可变集合或“冻结”集合。

标签: c# .net dictionary casting ienumerable


【解决方案1】:

你可以这样做:

var userDictionary = new Dictionary<int, List<User>>();
IDictionary<int, IEnumerable<User>> newDictionary = userDictionary.ToDictionary(p => p.Key, p => p.Value.AsEnumerable());

【讨论】:

  • 对于一个非常大的字典有什么性能影响?
  • @davenewza:如果你能对其进行基准测试,那是最好的;你的字典有多大?
  • @LuisFilipe:可能有数百个键,每个键都可以与数百个用户的列表相关联。
  • p.Value.AsEnumerable() 将不涉及任何成本,因为它返回对原始列表的引用。为数百个键复制字典根本不会花费太多时间。我刚刚在 0.05 秒内复制了一个包含 1000000 个条目的字典。
  • 请阅读我的更新答案:返回 IEnumerable 并不授予不变性,从您的问题来看,这似乎是您正在寻找的内容
【解决方案2】:

您可以返回 IEnumerable,但实际上它会是 List。开发人员可以将其转换为 List 并添加或删除项目

我认为您正在寻找 Immutable Collections

简而言之,它是一个 nuget 包,使我们能够使用/创建真正不可变的集合;这意味着任何集合更改都不会反映到暴露它们的内容。

编辑:转换为 IEnumerable 不授予不变性

鉴于 Guilherme Oliveira 答案,可以执行以下操作并向用户添加新用户

    var userDictionary = new Dictionary<int, List<User>>();
    userDictionary.Add(1, new List<User>
    {
        new User{ Name= "Joseph"},
    });
    IDictionary<int, IEnumerable<User>> newDictionary = userDictionary.ToDictionary(p => p.Key, p => p.Value.AsEnumerable());
    ((List<User>) newDictionary.Values.First()).Add(new User {Name = "Maria"});
    Console.WriteLine(newDictionary.Values.First().Count()); //now we have two users

【讨论】:

    【解决方案3】:

    您需要将其投影到新字典中,例如

    Dictionary<int, List<User>> myDictionary = ...;
    Dictionary<int, IEnumerable<User>> resultingDictionary = myDictionary.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<User>)kvp.Value)
    

    您无法执行从 Dictionary&lt;int, List&lt;User&gt;&gt;Dictionary&lt;int, IEnumerable&lt;User&gt;&gt; 的强制转换,因为如果可以,以下情况将是可能的:

    Dictionary<int, List<User>> myDictionary = ...;
    // Still a reference to the original dictionary
    Dictionary<int, IEnumerable<User>> castDictionary = myDictionary;
    
    // If the line above was possible, what would this do? (A HashSet<T> is not a List<T>)
    castDictionary.Add(5, new HashSet<User>());
    

    您可能还想看看接口上的协变和逆变,看看限制在哪里。

    【讨论】:

    • 实际上,当您将myDictionary 设置为castDictionary 时,您并没有投射它。如果要将值更改为另一种类型,则必须使用 AsEnumerable() 进行转换
    • 阅读该示例上方的行和该作业下方的评论,我说如果可能,它不是。
    猜你喜欢
    • 1970-01-01
    • 2013-06-11
    • 2013-01-01
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多