C# Unity 一个Key对应多个值的字典
1.目的
C# 中没有提供一个Key对应多个值的容器,需要自己封装一层,实现方式很多,可以使用链表去实现(分区域划分一个链表即可)但是这样做比较复杂但是频繁插入要比使用List性能好一些不用动态扩展长度,有机会可以分享一下如何使用链表实现更加高效率的一个Key对应多个值,今天分享一下简单快捷便于理解的。
2.OneToManyDic
c# 用有提供一个key对应一个值的字典Dictionary,在它的基础上进行拓展即可(继承Dictionary)
public class OneToManyDic<TKey, TValue> : Dictionary<TKey, List<TValue>> where TKey : notnull
为了避免Remove的时候List频繁创建,使用Queue队列对List进行缓存操作
private readonly Queue<List<TValue>> _cacheQueue = new Queue<List<TValue>>(); // 缓存listprivate readonly int _recyclingLimit = 120;public OneToManyDic(){}/// <summary>/// 设置最大缓存数量/// </summary>/// <param name="recyclingLimit">/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC./// 2:设置成0不控制数量,全部缓存/// </param>public OneToManyDic(int recyclingLimit){_recyclingLimit = recyclingLimit;}
3.完整代码
public class OneToManyDic<TKey, TValue> : Dictionary<TKey, List<TValue>> where TKey : notnull{private readonly Queue<List<TValue>> _cacheQueue = new Queue<List<TValue>>(); // 缓存listprivate readonly int _recyclingLimit = 120;public OneToManyDic(){}/// <summary>/// 设置最大缓存数量/// </summary>/// <param name="recyclingLimit">/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC./// 2:设置成0不控制数量,全部缓存/// </param>public OneToManyDic(int recyclingLimit){_recyclingLimit = recyclingLimit;}public bool Contains(TKey key, TValue value){TryGetValue(key, out var list);return list != null && list.Contains(value);}public void Add(TKey key, TValue value){if (!TryGetValue(key, out var list)){list = Fetch();list.Add(value);Add(key, list);return;}list.Add(value);}public TValue? First(TKey key){return !TryGetValue(key, out var list) ? default : list.FirstOrDefault();}public bool RemoveValue(TKey key, TValue value){if (!TryGetValue(key, out var list)){return true;}var isRemove = list.Remove(value);if (list.Count == 0){isRemove = RemoveByKey(key);}return isRemove;}public bool RemoveByKey(TKey key){if (!TryGetValue(key, out var list)){return false;}Remove(key);Recycle(list);return true;}public List<TValue>? GetValues(TKey key){return TryGetValue(key, out var list) ? list : null;}public new void Clear(){foreach (var keyValuePair in this) Recycle(keyValuePair.Value);base.Clear();}private List<TValue> Fetch(){return _cacheQueue.Count <= 0 ? new List<TValue>() : _cacheQueue.Dequeue();}private void Recycle(List<TValue> list){list.Clear();if (_recyclingLimit != 0 && _cacheQueue.Count > _recyclingLimit) return;_cacheQueue.Enqueue(list);}}
3.测试代码
OneToManyDic<int, string> dic = new OneToManyDic<int, string>();
dic.Add(1, "zzs");
dic.Add(1, "666");
dic.Add(2, "777");
dic.Add(2, "888");
dic.Add(2, "999");Console.WriteLine(dic.Count);
Console.WriteLine(dic.GetValues(1)?.Count);
Console.WriteLine(dic.GetValues(2)?.Count);Console.ReadKey();