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

C#中为作为参数传递的Action添加和移除方法问题

问题根源

C#里委托是引用类型,但默认参数传递是按值传递——也就是说你把testAction传给AddModifier的removeModEvent参数时,传递的是原委托的副本。你在方法里给removeModEvent添加新的委托方法,只会修改这个副本,外部的testAction完全没变化,所以调用testAction?.Invoke()只会执行初始的方法。

解决方案

方法1:用ref关键字传递委托参数

把方法的参数改成ref Action removeModEvent,这样传递的是原委托变量的引用,方法内的修改会直接作用到外部的testAction上:

修改后的调用代码

Action testAction = () => { Console.WriteLine("initial call"); };
// 调用时加ref关键字
damage.AddModifier(type, value, ref testAction);
testAction?.Invoke(); // 现在会输出"initial call"和"remove modifier"

修改后的方法定义

public void AddModifier(ModType type, float value, ref Action removeModEvent)
{
    AddModifier(type, value);
    
    Action e = null;
    e = () =>
    {
        Console.WriteLine("remove modifier");
        RemoveModifier(type, value);
        removeModEvent -= e;
    };
    removeModEvent += e;
}

方法2:用包装类持有委托(适合复杂场景)

如果不想用ref,可以定义一个简单的包装类来持有Action,因为类是引用类型,传递的是引用,修改内部的Action会同步到外部:

// 定义包装类
public class ActionWrapper
{
    public Action Action { get; set; }
}

// 调用方
var wrapper = new ActionWrapper { Action = () => { Console.WriteLine("initial call"); } };
damage.AddModifier(type, value, wrapper);
wrapper.Action?.Invoke();

// 修改后的方法定义
public void AddModifier(ModType type, float value, ActionWrapper wrapper)
{
    AddModifier(type, value);
    
    Action e = null;
    e = () =>
    {
        Console.WriteLine("remove modifier");
        RemoveModifier(type, value);
        wrapper.Action -= e;
    };
    wrapper.Action += e;
}
额外验证

调用testAction(或wrapper.Action)之后,再调用一次,只会输出"initial call"——因为lambda执行时已经把自己从委托链里移除了,符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:32:12