如何解决C#线程lambda内使用ref参数报CS1628错误的问题
核心矛盾
C# 中 lambda 闭包无法捕获ref参数,且值类型(结构体)在赋值、传参时会自动生成拷贝,导致线程内操作的不是原始实例。
方案1:泛型引用包装器(推荐,无额外拆箱开销,兼容所有C#版本)
通过泛型包装类存储实例引用,值类型仅发生一次装箱,无后续拆箱开销,同时保证线程内操作的是同一份实例,最终回写ref参数同步外部状态。
// 通用泛型包装类 public class TweenableWrapper<T> { public ITweenable<T> Instance { get; } public TweenableWrapper(ITweenable<T> instance) => Instance = instance; } // 修改后的TweenTo方法 public static void TweenTo<T>(ref ITweenable<T> obj, T target, double ms) { var wrapper = new TweenableWrapper<T>(obj); new System.Threading.Thread(() => { System.Threading.Thread.Sleep(5000); wrapper.Instance.DoStuff(5,5); // 回写实例保证外部原始变量同步更新 obj = wrapper.Instance; }).Start(); }
方案2:Unsafe 指针操作(适合无装箱需求场景,C# 7.2+支持)
借助System.Runtime.CompilerServices.Unsafe类直接传递实例指针,完全避免装箱开销,需自行保证实例在线程运行期间不会被GC回收,否则会触发野指针异常。
using System.Runtime.CompilerServices; using System.Threading; public static unsafe void TweenTo<T>(ref ITweenable<T> obj, T target, double ms) { // 取实例指针存储 void* pObj = Unsafe.AsPointer(ref obj); new Thread(() => { Thread.Sleep(5000); // 恢复引用后操作 ref ITweenable<T> instance = ref Unsafe.AsRef<ITweenable<T>>(pObj); instance.DoStuff(5,5); }).Start(); }
你之前的测试方案失效原因
直接将obj赋值给闭包捕获的变量时,若obj是值类型会直接生成拷贝,后续操作的都是副本,自然无法同步到原始实例。
内容的提问来源于stack exchange,提问作者CoderMuffin
相关产品推荐
相关产品推荐

