我正在尝试更新异步方法回调中由ref传递给我的值。
// this Main method parameters are given and can not be changed.
public static void Main(ref System.String msg)
{
// here we should invoke an async code,
// which updates the msg parameter.
}
现在,我认识你can not pass ref values to async methods。但是我仍然想以某种方式更新该ref值,而不会阻塞我的UI线程。 在我看来,这是不合理的。
我尝试过的事情:
// Our entry point
public static void Main(ref System.String msg)
{
Foo(msg);
}
// calls the updater (can't use 'await' on my entry point. its not 'async method')
static async void Foo(ref System.String m)
{
var progress = new Progress<string>(update => { m = update; });
await Task.Run(() => MyAsyncUpdaterMethod(progress));
}
// update the variable
static void MyAsyncUpdaterMethod(IProgress<string> progress)
{
Thread.Sleep(3000);
if (progress != null)
{
progress.Report("UPDATED");
}
}
显然,由于无法将msg
参数用于异步方法lambada表达式,因此无法使用。我的问题是。会怎样。如何做到这一点。
是否可以设置一个包含引用参数的全局静态变量,并在回调中使用它?
答案 0 :(得分:0)
您想要突变。 string
是不可变的。一种解决方案是为该字符串创建一个新的可变容器。
public class StringContainer
{
public string String { get; set; }
}
static async void Foo(StringContainer container)
{
var progress = new Progress<string>(update => container.String = update);
await Task.Run(() => MyAsyncUpdaterMethod(progress));
}
答案 1 :(得分:0)
您仍在同步呼叫Foo
。我会尝试这样的事情:
public static void Main(ref string msg)
{
msg = Foo(msg);
}
public static string Foo(string msg)
{
return Task.Run(async ()=> await DoAsyncWork(msg)).Result;
}
async Task<string> DoAsyncWork(string msg)
{
string result = await DoMaybeSomeOtherTask(msg);
return result;
}
现在,我们不知道它是控制台还是窗口应用程序。如果它是窗口应用程序,则不应在Task上调用Result
或Wait()
方法,因为它可能导致死锁。如果是控制台应用程序,则可以执行此操作。
如果是窗口应用程序,则应运行Task.Run稍有不同。您也可以使用StringBuilder
代替string
。
答案 2 :(得分:0)
好吧,我认为您没有理由不能只单独计算答案,然后最后将其分配给.mat-snack-bar-container{
white-space: pre-line !important;
}
值:
ref
只需记住在各处添加public static void Main(ref System.String msg)
{
var result = Foo(msg).GetAwaiter().GetResult();
msg = result;
}
private static async Task<string> Foo(string msg)
{
await Task.Delay(3000).ConfigureAwait(false);
return "UPDATED";
}
即可避免死锁。
答案 3 :(得分:0)
我仍然想以某种方式更新该ref值,而不会阻塞我的UI线程。在我看来,这是不合理的。
这不可能。
从线程堆栈的角度考虑它。当将ref
参数传递给方法时,只能将该参数写入该堆栈帧(或以下)中。同时,异步代码通过在操作完成之前返回到调用方法来工作。因此,存在一个无法逾越的鸿沟:必须保留堆栈帧以写入ref
,并且必须弹出堆栈帧以使其异步。这就是ref
与异步代码不兼容的原因。
通常,ref
不是指针。它在逻辑上相似,但是.NET是一种“安全”的编程语言,这就是为什么存在“ ref
必须存在于堆栈框架中”规则的原因。 .NET故意防止将ref
复制到全局变量,例如在弹出堆栈框架后可以对其进行更新的情况。
通过获取指向对象的指针并以这种方式进行操作(使用unsafe
代码),您可能能够做一些危险的事情,但是在走那条路线之前,我会想很久很努力。
没有unsafe
代码,您的选择是:
ref
参数。当然,核心问题是Main
方法签名。只是没有意义。方法签名是同步的,并且必须返回,然后UI才能进行更新。它确实应该具有异步签名。