【问题标题】:Adding items to an ImmutableList<T> inside an ImmutableDictionary<TKey, TValue>将项目添加到 ImmutableDictionary<TKey, TValue> 内的 ImmutableList<T>
【发布时间】:2021-02-02 13:57:34
【问题描述】:

我似乎无法弄清楚如何将项目添加到 ImmutableList 内的 ImmutableDictionary。

我有以下变量:

ImmutableDictionary<string, ImmutableList<string>> _attributes = ImmutableDictionary<string, ImmutableList<string>>.Empty;

我试图在列表中添加一个值:

string[] attribute = line.Split(':');
if (!_attributes.ContainsKey(attribute[0]))
    _attributes = _attributes.Add(attribute[0], ImmutableList<string>.Empty);
if (attribute.Length == 2)
    _attributes[attribute[0]] = _attributes[attribute[0]].Add(attribute[1]);

但是,我收到一条错误消息,指出 ImmutableList 没有设置器。如何在不重建整个字典的情况下替换字典中的列表?

【问题讨论】:

标签: c# .net .net-5 c#-8.0 immutable-collections


【解决方案1】:

ImmutableCollections 提供了许多不同的方式来构造它们。
一般指导是首先填充它们,然后使它们不可变。

Create + AddRange

ImmutableDictionary<string, string> collection1 = ImmutableDictionary
    .Create<string, string>(StringComparer.InvariantCultureIgnoreCase)
    .AddRange(
        new[]
        {
            new KeyValuePair<string, string>("a", "a"),
            new KeyValuePair<string, string>("b", "b"),
        });

我们创建了一个空集合,然后创建了另一个具有一些值的集合。

Create + Builder

ImmutableDictionary<string, string>.Builder builder2 = ImmutableDictionary
    .Create<string, string>(StringComparer.InvariantCultureIgnoreCase)
    .ToBuilder();

builder2.AddRange(
    new[]
    {
        new KeyValuePair<string, string>("a", "a"),
        new KeyValuePair<string, string>("b", "b"),
    });

ImmutableDictionary<string, string> collection2 = builder2.ToImmutable();

我们创建了一个空集合,然后将其转换为构建器。
我们已经用值填充了它。
最后我们构建了不可变集合。

CreateBuilder

ImmutableDictionary<string, string>.Builder builder3 = ImmutableDictionary
    .CreateBuilder<string, string>(StringComparer.InvariantCultureIgnoreCase);

builder3
    .AddRange(
        new[]
        {
            new KeyValuePair<string, string>("a", "a"),
            new KeyValuePair<string, string>("b", "b"),
        });

ImmutableDictionary<string, string> collection3 = builder3.ToImmutable();

这是前一个案例的缩写形式 (Create + ToBuilder)

CreateRange

ImmutableDictionary<string, string> collection4 = ImmutableDictionary
    .CreateRange(new[]
    {
        new KeyValuePair<string, string>("a", "a"),
        new KeyValuePair<string, string>("b", "b"),
    });

这是第一种情况的简写形式 (Create + AddRange)

ToImmutableDictionary

ImmutableDictionary<string, string> collection5 = new Dictionary<string, string>
{
    { "a", "a" },
    { "b", "b" }
}.ToImmutableDictionary();

最后但并非最不重要的是,我们使用了转换器。

【讨论】:

  • 这个问题/答案被低估了。只有 1/2 的赞成票。谢谢!
  • @PedroCoelho 感谢您的支持,如果您发现我的帖子有价值,我很高兴。
【解决方案2】:

答案就在我的眼皮底下。就像我在添加项目时需要调用 Add 并覆盖原始变量一样,我需要在 Dictionary 上调用SetItem。有道理!

【讨论】:

  • 不,你误会了。 SetItem 实际上是一个工厂方法,它将从原始集合中创建一个新的不可变集合,其中给定的键已经更新为指定的值。
  • 不,我理解正确,我只需要这样做:_attributes = _attributes.SetItem (attribute[0], _attributes[attribute[0]].Add(attribute[1]));跨度>
【解决方案3】:

您可以使用 ImmutableDictionary.TryGetValue 方法,将字典查找次数从 3 次减少到 2 次。

var _attributes = ImmutableDictionary.Create<string, ImmutableList<string>>();

string[] parts = line.Split(':');
if (parts.Length == 2)
{
    string attributeName = parts[0];
    string attributeValue = parts[1];

    if (_attributes.TryGetValue(attributeName, out var list))
    {
        _attributes = _attributes.SetItem(attributeName, list.Add(attributeValue));
    }
    else
    {
        _attributes = _attributes.Add(attributeName, ImmutableList.Create(attributeValue));
    }
}

如果您想将具有线程安全性的字典作为原子操作更新,您可以使用ImmutableInterlocked.AddOrUpdate 方法:

ImmutableInterlocked.AddOrUpdate(ref _attributes, attributeName,
    _ => ImmutableList.Create(attributeValue),
    (_, existing) => existing.Add(attributeValue));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-14
    • 2012-07-25
    • 1970-01-01
    • 2021-06-12
    相关资源
    最近更新 更多