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

C#中,在作为参数的匿名函数内使用函数引用结果是否安全?

核心问题:匿名函数内直接使用外部函数返回的引用类型是否安全?

两种写法的编译差异解析

第一种先初始化result = null的写法能编译,而第二种直接赋值的写法报错Cannot use local variable 'result' before it is declared,本质是C#的明确赋值规则:

  • 当在闭包中引用局部变量时,编译器要求变量必须被明确赋值过(哪怕是赋值为null),否则会判定为“使用未声明的变量”。
  • 第二种写法中,result的声明和赋值在同一行,闭包引用它时,编译器无法确定赋值操作是否在闭包执行前完成,因此直接报错。

关于安全性的核心结论

这种写法在你的Unity动画场景中是安全的,但有个关键前提:外部函数(FunctionA/TestB)是同步返回结果,再将匿名函数加入延迟执行队列。

原因在于C#闭包捕获的是变量的引用,而非变量的当前值:

  1. 调用instanceA.FunctionA(...)时,先将匿名函数传入,FunctionA内部把匿名函数加入动画队列,随后同步返回ClassA实例,此时result变量已经被赋值为该实例的引用。
  2. 数秒后匿名函数执行时,它访问的result变量已经指向FunctionA返回的实例,只要FunctionA返回的不是null,就不会触发NullReferenceException。

你的测试示例中TestB未调用handler,所以看不到后续输出,但实际场景中TestB会延迟执行handler,此时x已经被赋值为TestB返回的ResultClass实例,访问x.a是安全的。

代码健壮性优化建议

虽然这种写法在当前场景下安全,但从可读性和维护性角度,更推荐将返回结果作为参数传入匿名函数,彻底避免依赖变量捕获的时序问题:

// 修改TestB签名,接受带参数的Action
ResultClass TestB(Action<ResultClass> handler)
{
    var a = new ResultClass();
    a.a = 100;
    print("1");
    // 将返回实例作为参数传入handler
    handler?.Invoke(a);
    return a;
}

// 调用时无需捕获外部变量
public void FunctionA()
{
    ResultClass x = TestB(res => {
        res.a += 200;
        print("2 x.a = " + res.a);
    });
}

这种写法逻辑更清晰,不需要依赖外部变量的赋值时序,也避免了闭包捕获可能带来的意外问题(比如变量被意外修改)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 12:07:32