You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Action<T>的唯一性判定与ConcurrentDictionary存储方案

解决方案

1. 自定义唯一标识键

先写一个ActionKey密封类,专门用来封装Action的唯一性信息,重写Equals和GetHashCode来精准匹配你的规则:

public sealed class ActionKey : IEquatable<ActionKey>
{
    public object Target { get; }
    public MethodInfo Method { get; }

    private ActionKey(object target, MethodInfo method)
    {
        Target = target;
        Method = method;
    }

    public static ActionKey Create<T>(Action<T> action)
    {
        var method = action.Method;
        // 静态方法的Target是null,这时候用方法的声明类型当标识的一部分
        var target = action.Target ?? method.DeclaringType;
        return new ActionKey(target, method);
    }

    public bool Equals(ActionKey other)
    {
        if (other is null) return false;
        // 先比实例/类型,再比方法,确保唯一
        return ReferenceEquals(Target, other.Target) && Method.Equals(other.Method);
    }

    public override bool Equals(object obj) => Equals(obj as ActionKey);

    public override int GetHashCode()
    {
        // 把Target和Method的哈希值组合起来,大幅降低冲突概率
        return HashCode.Combine(Target, Method);
    }
}

逻辑很清晰:

  • 实例方法:用具体对象实例+方法信息当标识,不同实例的同方法会被当成不同键
  • 静态方法:用方法的声明类型+方法信息当标识,不管怎么创建Action,同一静态方法的键都是一样的,确保只存一次

2. 用非泛型ConcurrentDictionary存储

因为不同泛型参数的Action<T>没法直接塞进强类型泛型字典,所以用ConcurrentDictionary<ActionKey, Delegate>来存,所有泛型Action都能转成Delegate:

private readonly ConcurrentDictionary<ActionKey, Delegate> _actionStore = new();

public void RegisterAction<T>(Action<T> action)
{
    var key = ActionKey.Create(action);
    // TryAdd是原子操作,键不存在才会添加成功,完美解决无重复存储
    var isAdded = _actionStore.TryAdd(key, action);
    // 按需求输出valid: true
    if (isAdded)
    {
        Console.WriteLine($"valid: true > 已注册Action: {action.Method.Name}");
    }
    else
    {
        Console.WriteLine($"valid: false > 重复Action: {action.Method.Name}");
    }
}

3. 测试验证

跑个测试看看规则是否生效:

public class DemoClass
{
    public void InstanceMethod(int num) { }
    public static void StaticMethod(string str) { }
}

// 测试场景
var demo1 = new DemoClass();
var demo2 = new DemoClass();

// 不同实例的同实例方法,都能注册成功
RegisterAction<int>(demo1.InstanceMethod); // valid: true
RegisterAction<int>(demo2.InstanceMethod); // valid: true

// 同一静态方法多次注册,只有第一次成功
RegisterAction<string>(DemoClass.StaticMethod); // valid: true
RegisterAction<string>(DemoClass.StaticMethod); // valid: false

// 不同的匿名方法,即使逻辑类似也会被当成不同Action
RegisterAction<int>(x => Console.WriteLine(x)); // valid: true
RegisterAction<int>(x => Console.WriteLine(x * 2)); // valid: true

核心优势

  • 解决泛型不兼容:用Delegate作为值类型,兼容所有Action<T>
  • 精准唯一性:完全匹配你要的规则——实例方法按实例区分,静态方法全局唯一
  • 线程安全:ConcurrentDictionary的TryAdd是原子操作,并发场景下也不会出现重复存储

内容的提问来源于stack exchange,提问作者monty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:24:53