【发布时间】:2021-10-28 10:27:50
【问题描述】:
我正在尝试编写一个补间类,为此我有一个静态的Tweener.TweenTo 方法。在其中,我们启动一个线程以不阻碍外部操作。该方法如下所示:
public static void TweenTo<T>(ref ITweenable<T> obj, T target, double ms)
{
new System.Threading.Thread(() => {
System.Threading.Thread.Sleep(5000)
obj.DoStuff(5,5) //throws exception because obj is a ref parameter
}).Start()
}
我知道在 lambda 中使用 ref 参数意味着它可能是一个悬空引用,但我需要能够使用它以防用户尝试将值类型或结构传递给方法。我尝试过使用参数化线程启动,但这会将事情强制到一个我不能使用的对象(拆箱等)。我也尝试过使用包含指向它的指针的包装类,但这会在以后遇到复杂情况。
我想要一种在线程中使用此 ref 参数的方法,并理想地在其中保留其生命周期。
任何帮助表示赞赏:D
编辑:Olivier 的答案接近我的需要,但 MyClass 在某些情况下会是一个结构,并且它会尽可能地复制。这意味着它将丢失引用并从错误的实例中给出值。
编辑 2:示例结构
public struct MyStruct : ITweenable<T> {
int x;
int y;
public MyStruct(int X) {
this.x=X;
}
public void DoStuff(int newX, int newY) {
this.x=newX;
this.y=newY;
}
}
public interface ITweenable<T> {
void DoStuff(int newX, int newY);
}
编辑 3:我还没有测试过这个,所以当我有的时候我会给出它作为答案 - 现在已经测试过,不起作用:
public static void TweenTo<T>(ITweenable<T> obj, T target, double ms)
{
Func<ITweenable<T>> getTween = ()=>{return obj;}
new System.Threading.Thread(() => {
System.Threading.Thread.Sleep(5000)
getTween().DoStuff(5,5);
}).Start()
}
【问题讨论】:
-
这里为什么需要使用ref?而且您可能应该使用任务库而不是线程。
-
我宁愿使用
Parameterized ThreadStart并将其显式转换回来。你不会有装箱\拆箱,只有转换,因为我猜ITweenable<T> obj是一个引用类型(装箱\拆箱只发生在值类型上)。此外,在大多数情况下,使用 Async\Await over Threads 的任务在资源效率和代码可读性方面更可取。 -
Ref 是必需的以保留结构引用(请参阅上面的编辑)
-
“因为 obj 是 ref 参数而引发异常”是什么意思?什么例外? minimal reproducible example 可以更轻松地为您提供帮助,同时满足精确 要求。
-
(顺便说一句,我期望
ITweenable<T>是一个接口,因此不是一个值类型。即使实现是一个值类型,使用接口会导致装箱,参数的编译时类型需要为ITweenable<T>。)
标签: c# multithreading lambda parameters ref