kennylovecode Posted June 11, 2025 Posted June 11, 2025 Recently, I have been looking at some previous source code and found that it has been heavily used ThreadSafeDictionary Of course, you can tell from the name that it is for thread safety Then I discovered in a large amount of code GameState[] array = Server.GamePool.Values; Of course, this is also for thread safety, copying a new copy of the dictionary value into memory first. So I may have found about a hundred sentences of this repetitive code. So I refactored a ThreadSafeDictionary class But I'm not quite sure what problems it might have, so I'm looking at everyone's experience. Here is my code: Quote using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; /// <summary> /// 线程安全字典,提供安全遍历功能 /// </summary> public class ThreadSafeDictionary<TKey, TValue> : ConcurrentDictionary<TKey, TValue> { /// <summary> /// 获取值的安全副本进行遍历 /// </summary> public IEnumerable<TValue> ValuesSnapshot { get { return Values.ToArray(); } } /// <summary> /// 获取键值对的安全副本进行遍历 /// </summary> public IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairsSnapshot { get { return ToArray(); } } /// <summary> /// 安全地遍历所有值并对每个值执行操作 /// </summary> public void ForEachValue(Action<TValue> action) { if (action == null) return; foreach (var value in ValuesSnapshot) { if(value == null) continue; action(value); } } /// <summary> /// 安全地遍历所有键值对并对每个键值对执行操作 /// </summary> public void ForEach(Action<KeyValuePair<TKey, TValue>> action) { if (action == null) throw new ArgumentNullException(nameof(action)); foreach (var pair in KeyValuePairsSnapshot) { action(pair); } } /// <summary> /// 安全地遍历所有值并返回转换后的集合 /// </summary> public IEnumerable<TResult> SelectValues<TResult>(Func<TValue, TResult> selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); foreach (var value in ValuesSnapshot) { yield return selector(value); } } /// <summary> /// 安全地遍历所有键值对并返回转换后的集合 /// </summary> public IEnumerable<TResult> Select<TResult>(Func<KeyValuePair<TKey, TValue>, TResult> selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); foreach (var pair in KeyValuePairsSnapshot) { yield return selector(pair); } } // 新增方法:简化Add操作 /// <summary> /// 添加键值对,如果键已存在则覆盖 /// </summary> public void AddOrUpdate(TKey key, TValue value) { base[key] = value; } // 新增方法:简化Add操作,不覆盖已有值 /// <summary> /// 尝试添加键值对,如果键已存在则不添加 /// </summary> public bool Add(TKey key, TValue value) { return TryAdd(key, value); } // 新增方法:简化Remove操作 /// <summary> /// 移除指定键的元素 /// </summary> public bool Remove(TKey key) { return TryRemove(key, out _); } // 新增方法:获取值,如果不存在则返回默认值 /// <summary> /// 获取指定键的值,如果键不存在则返回默认值 /// </summary> public TValue GetOrDefault(TKey key, TValue defaultValue = default) { return TryGetValue(key, out TValue value) ? value : defaultValue; } // 新增方法:获取值,如果不存在则添加 /// <summary> /// 获取指定键的值,如果键不存在则添加新值 /// </summary> public TValue GetOrAdd(TKey key, TValue value) { return base.GetOrAdd(key, value); } // 新增方法:获取值,如果不存在则添加(使用工厂方法) /// <summary> /// 获取指定键的值,如果键不存在则使用工厂方法创建新值 /// </summary> public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) { return base.GetOrAdd(key, valueFactory); } // 新增方法:清空字典 /// <summary> /// 清空字典中的所有元素 /// </summary> public void Clear() { base.Clear(); } } This is about its calling: public static void Send(IPacket packet, ushort withoutMapId = 0, uint withoutUID = 0) { GameStatePool.ForEachValue((gameState) => { if (gameState.Map.ID == withoutMapId) return; if (gameState.Entity.UID == withoutUID) return; gameState.Send(packet); }); } Haha, I have a code cleanliness obsession. I don't like to write a repetitive code sentence hundreds of times. But I'm not sure what new problems it will bring, anyway it's just a learning code. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.