如何为实现同一接口的多种类型制作通用字典?

时间:2018-12-10 21:56:18

标签: c#

当前我遇到Dictionary<ulong, IStoreableObject>的问题,当实现IStoreableObject的2种不同类型具有相同的ID时,问题就来了。

我想出了类似这样的方法来“修复它”,但是我不确定这是一个不好的设计,线程不安全还是会有其他问题,也许有人可以帮助我弄清楚如何为实现相同接口的不同类型正确分隔字典,以便它们的ID冲突不会有问题?到目前为止,这是我的代码:

using System.Collections.Generic;

namespace SqlExpress
{
    internal sealed class Cache<T> where T : IStoreableObject
    {
        private readonly Dictionary<ulong, T> _cache = new Dictionary<ulong, T>();
        private readonly object _lock = new object();
        private static Cache<T> _instance = null;

        internal static Cache<T> Instance
        {
            get
            {
                if (_instance is null)
                {
                    _instance = new Cache<T>();
                }
                return _instance;
            }
        }

        private Cache() { }

        internal void AddOrUpdate(T obj)
        {
            if (_cache.ContainsKey(obj.Id))
            {
                _cache[obj.Id] = obj;
            }
            else
            {
                lock (_lock)
                {
                    _cache.Add(obj.Id, obj);
                }
            }
        }

        internal T Get(ulong id)
        {
            if (_cache.ContainsKey(id))
            {
                return _cache[id];
            }
            return default(T);
        }

        internal void Remove(ulong id)
        {
            if (_cache.ContainsKey(id))
            {
                _cache.Remove(id);
            }
        }
    }
}

预期行为:

假设我们有两个对象FooBar,它们都实现了IStoreableObject

Foo的2+个对象不能具有相同的ID,Bar的2+个对象也不能具有相同的ID。无论如何,Foo和Bar高速缓存不应相互关联,因此,如果Cache<Foo>中的对象与Cache<Bar>中的另一个对象具有相同的ID,则不会发生任何不良情况。 Dictionary<ulong, IStoreableObject>无法做到这一点,因为所有基础类型都在同一个缓存中,我希望它们位于不同的缓存中,并且每个缓存应只存在一次,我的意思是,应该仅存在1个Cache<Foo>以及1 Cache<Bar>

1 个答案:

答案 0 :(得分:0)

正如其他人指出的那样,防止重复密钥的唯一方法是通过某种方式在密钥中包含Type

您可以通过嵌套字典来做到这一点,就像这样:

Dictionary<Type, Dictionary<ulong, T>> _cache

但是我可能会使用ValueTuple

Dictionary<(Type, ulong), T> _cache

还有一个字符串串联方法$"{typeof(T).Name}_{id}",但是如果该类型碰巧具有相同的名称但位于单独的命名空间中,则该方法又可以生成重复项。因此,最好考虑完整的Type

另外,考虑使用ConcurrentDictionary,因为您似乎在这里处于多线程环境中。