Jump to content
Returning Members: Password Reset Required ×

Recommended Posts

Posted

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.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...