我试图创建一个视图模型,其中一些属性从后台线程加载.

对于这项任务,我在NotifyTaskCompletion<T>上找到了this old MSDN article by Stephen Cleary.第A Better Approach节中的代码列表"图4"看起来像这样:

public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
{
    public NotifyTaskCompletion(Task<TResult> task)
    {
        Task = task;
        if (!task.IsCompleted) {
            var _ = WatchTaskAsync(task);
        }
    }

    private async Task WatchTaskAsync(Task task) {
        [...]
    }

    [...]
}

现在我想知道--如果我有一个像WatchTaskAsync这样的方法,我永远不想等待(not等待该任务本质上是整个课程的目的),那么首先创建方法async void有什么区别吗?

我知道difference between await and discard,但在这个特定的上下文中,只有在我不想等待它完成的情况下才调用该方法,创建那个Task对象只是为了每次丢弃它是没有意义的,不是吗?

推荐答案

Discarding a Task is called fire-and-forget.
Launching an async void operation is called fire-and-crash.

出现错误时会出现差异.被解雇并被遗忘的Task个例外永远不会出现.它将永远处于人们的关注之下.async void操作的异常将在捕获的SynchronizationContext上重新抛出,所有已知的SynchronizationContext都会大声传播其异常,弹出消息框等.如果没有SynchronizationContext,就像在控制台应用程序中一样,异常将在ThreadPool上重新抛出,导致进程在错误发生几毫秒后崩溃.

如果您有Task,并且希望将其视为async void,最简单的做法是在ThreadPool上将其await:

ThreadPool.QueueUserWorkItem(async _ => await task);

ThreadPool.QueueUserWorkItem方法不理解Deliverc委托,所以这个Deliverc委托实际上是async void.由于ThreadPool没有可供async void捕获的同步上下文,因此您会出现崩溃行为.

听起来很糟糕,但可以说它比替代方案更好.最好是出现错误消息导致崩溃,而不是导致无响应的应用程序自动挂起而不提供任何反馈.

Csharp相关问答推荐

为什么在GuardationRule的收件箱函数中,decode.TryParse(valueString,out valueParsed)在给出1.0.1时返回true?

使用C#中的Shape API从Azure目录获取所有用户

在C#中使用in修饰符

使用命令初始化可绑定属性

自动映射程序在GroupBy之后使用项目

如何测量在使用UTF8而不是C#中的UTF16编码字符串时内存使用量的增长

如何使用C#中的主构造函数功能使用多个构造函数?

当前的文化决定了错误的文化

如何在Cosmos SDK中控制超时、重试和重试之间的延迟?

使用Entity Framework6在对象中填充列表会导致列表大多为空

Polly重试URL复制值

为什么@rendermode Interactive Auto不能在.NET 8.0 Blazor中运行?

在C#中有没有办法减少大型数组中新字符串的分配?

.NET Google Workspace API获取错误CS0266

序列化过程中的死循环

ASP.NET核心8:app.UseStaticFiles()管道执行顺序

在Unity C#中按键点击错误的参数

在使用xUnit和Mock执行单元测试时,控制器ViewResult返回空的Model集合

如何将行添加到DataGrid以立即显示它?

在c#中,使用Okta和Blazor时,LocalReDirect()陷入循环,出现错误&请求太多.