C# 9静态Lambda为何仍存在Target属性值?
C# 9静态Lambda的Action.Target不为null的问题及解决办法
问题现象
C# 9引入的static Lambda本应避免捕获外部实例状态,但将其赋值给Action后,检查.Target属性时会发现它并非null——而是指向编译器自动生成的嵌套静态类实例,这和直接指向静态方法的Action行为不一致。
示例代码:
Action action = static () => Console.WriteLine("test"); if(action.Target != null) { // 实际会进入此分支,与预期不符 }
这种情况会破坏你构建的弱引用事件系统逻辑:原本通过.Target == null判断无需处理弱引用,但静态Lambda的.Target会导致该判断失效。
原因分析
编译器处理无捕获的static Lambda时,并未直接将其映射为独立的静态方法,而是生成了一个命名类似<>c的嵌套静态类,在该类中实现Lambda逻辑,并创建该类的静态单例实例。最终Action指向的是这个单例实例的方法,因此.Target会指向该静态类实例,而非null。
而直接引用静态方法时,Action的.Method本身是静态方法,.Target自然为null。
解决办法
方案1:修正判断逻辑
结合.Method.IsStatic和.Target的类型特征来判断:
- 如果委托指向的方法是静态的,即使
.Target不为null,也不会持有外部业务实例的引用(编译器生成的静态类实例不会造成内存泄漏) - 额外判断
.Target是否为编译器生成的闭包类(通过类型名称包含<>c标记识别)
修改后的判断代码:
Action action = static () => Console.WriteLine("test"); bool requiresWeakReference = !(action.Method.IsStatic || (action.Target != null && action.Target.GetType().Name.Contains("<>c") && action.Method.IsStatic)); if (requiresWeakReference) { // 对外部实例使用弱引用处理 }
方案2:直接使用静态方法替代Lambda
如果场景允许,直接将静态方法赋值给Action,此时.Target会保持为null,符合最初的判断逻辑:
static void TestAction() => Console.WriteLine("test"); Action action = TestAction; // 此时action.Target == null,判断逻辑正常生效
内容的提问来源于stack exchange,提问作者trampster
相关产品推荐
相关产品推荐

