【问题标题】:C# Nested ConcurrentDictionary wrapperC# 嵌套 ConcurrentDictionary 包装器
【发布时间】:2018-06-17 22:57:29
【问题描述】:

似乎没有办法嵌套 ConcurrentDictionary 以便它们共享一个锁

我正在尝试创建一个类,它将用锁包装一个 3 深的嵌套字典

这样我就可以执行 NestedDict[k1][k2][k3] 并以并发安全的方式获取值 并执行 NestedDict[k1][k2] 并获得 ConcurrentDictionary 或等效项。

我不是在寻找继承或组合ConcurrentDictionary<Tuple<TK1,TK2,TK3>,V> 的解决方案,因为它不一样,它不允许我有效地获取 dict[k1, k2] 的所有键

如何实现?

是否有现有的通用库/代码显示这种嵌套字典实现(包括迭代器等)?

【问题讨论】:

  • 你希望这个类实现什么契约? (如:它应该保证什么线程安全)也许并发字典包装器会在这里做。您不必继承本身,您也可以实现 IDictionary 接口并使用私有字典。
  • 无论如何,使用三层嵌套泛型几乎总是一种代码味道,我强烈建议您重构该代码并简化它。
  • 合同应该与 ConcurrentDictionary 的合同完全相同,但是我不确定从嵌套 ConcurrentDictionarys 继承的锁定含义。我可以像你说的那样自己实现 IDictionary 但我的问题仍然是如何覆盖嵌套访问 []
  • 你能实现this[K1, K2, K3]吗?
  • 这感觉像是一个 XY 问题 - meta.stackexchange.com/questions/66377/what-is-the-xy-problem为什么你需要这个?

标签: c# c#-7.0


【解决方案1】:

这是您可以采取的一种方法

using System;
using System.Collections.Concurrent;

public class Program
{
    public class NestedDictionary<TK1, TK2, TK3, TValue>
    {
        private readonly ConcurrentDictionary<Tuple<TK1, TK2, TK3>, TValue> storage = new ConcurrentDictionary<Tuple<TK1, TK2, TK3>, TValue>();
        public TValue this[TK1 key1, TK2 key2, TK3 key3]
        {
            get => this.storage[new Tuple<TK1, TK2, TK3>(key1, key2, key3)];
            set => this.storage[new Tuple<TK1, TK2, TK3>(key1, key2, key3)] = value;
        }

        public bool TryGetValue(TK1 key1, TK2 key2, TK3 key3, out TValue value)
        {
            return this.storage.TryGetValue(new Tuple<TK1, TK2, TK3>(key1, key2, key3), out value);
        }

        public bool TryAdd(TK1 key1, TK2 key2, TK3 key3, TValue value)
        {
            return this.storage.TryAdd(new Tuple<TK1, TK2, TK3>(key1, key2, key3), value);
        }

        // etc etc

    }

    public static void Main()
    {
        NestedDictionary<int, bool, DateTime, string> d = new NestedDictionary<int, bool, DateTime, string>();
        d[1, false, new DateTime(2018, 6, 18)] = "Hello";
        d[1, true, new DateTime(2018, 6, 18)] = "World";
        d[2, false, new DateTime(2018, 6, 18)] = "Foo";
        d[2, false, new DateTime(2018, 6, 19)] = "Bar";
        Console.WriteLine(d[1, true, new DateTime(2018, 6, 18)]); // World
    }
}

您甚至可以在紧要关头实现 IDictionary 方法。鉴于 Tuple 在内部为您提供了来自复合键的哈希码的良好分布,它应该具有与嵌套中的三个独立字典非常相似的性能特征。

【讨论】:

  • 不需要包装器 - 这些方法可以是扩展方法。如果键是 ValueTuple,则元组语法可能比包装器或扩展方法更简单,例如var dict=new ConcurrentDictionary&lt;(int,bool,DateTime), string&gt;(); dict[ (1,false,new DateTime(....))]= "Hello";
  • 谢谢,问题在于 NestedDictionary 没有实现完整的 Dictionary 接口(即迭代器等)。
  • 您的迭代器(如键)需要是一个 ienumerable,因此在您希望自定义使用者采用三个参数的情况下,这对我来说毫无意义。如果您对键是一个元组感到满意,那么您可以从 ConcurrentDictionary,TValue> 继承 NestedDictionary,然后在这些重载上使用 'this' 而不是 'this.storage'。
  • 继承或组合ConcurrentDictionary,TValue>不一样,它不会让我ie高效获取dict[k1,k2]的所有key
  • A Dictionary 不会让您看到所有以 'A' 开头的键,即使字符串(至少在概念上)是一个有序的字符集合。请更新您的问题以解释您想要做什么。您使用“等”这个词的范围太大,我们无法提出任何进一步的明智建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多