C# 对Dispatcher.BeginInvoke()使用async/await

C# 对Dispatcher.BeginInvoke()使用async/await,c#,wpf,asynchronous,lambda,async-await,C#,Wpf,Asynchronous,Lambda,Async Await,我有一个带有一些代码的方法,可以执行等待操作: public async Task DoSomething() { var x = await ...; } 我需要在调度程序线程上运行该代码。现在,Dispatcher.BeginInvoke()是可等待的,但我不能将lambda标记为async,以便从内部运行wait,如下所示: public async Task DoSomething() { App.Current.Dispatcher.BeginInvoke(async

我有一个带有一些代码的方法,可以执行
等待
操作:

public async Task DoSomething()
{
    var x = await ...;
}
我需要在调度程序线程上运行该代码。现在,
Dispatcher.BeginInvoke()
是可等待的,但我不能将lambda标记为
async
,以便从内部运行
wait
,如下所示:

public async Task DoSomething()
{
    App.Current.Dispatcher.BeginInvoke(async () =>
        {
            var x = await ...;
        }
    );
}
public async Task<int> DoSomethingWithUIAsync()
{
    await Task.Delay(100);
    this.Title = "Hello!";
    return 42;
}

public async Task DoSomething()
{
    var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
        DoSomethingWithUIAsync);
    Debug.Print(x.ToString()); // prints 42
}
在内部
async
,我得到了错误:

无法将lambda表达式转换为类型“System.Delegate”,因为它不是委托类型


如何从
Dispatcher.BeginInvoke()
中使用
async

使用
Dispatcher.Invoke()

这可能引入了一个模糊的bug。此代码:

public async Task DoSomething()
{
    App.Current.Dispatcher.Invoke(async () =>
    {
        var x = await ...;
    });
}
使用
Dispatcher.Invoke
的覆盖形式,在这种特殊情况下,它接受
异步void
lambda。这可能会导致相当意外的行为,因为它通常发生在

您可能正在寻找类似以下内容:

public async Task DoSomething()
{
    App.Current.Dispatcher.BeginInvoke(async () =>
        {
            var x = await ...;
        }
    );
}
public async Task<int> DoSomethingWithUIAsync()
{
    await Task.Delay(100);
    this.Title = "Hello!";
    return 42;
}

public async Task DoSomething()
{
    var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
        DoSomethingWithUIAsync);
    Debug.Print(x.ToString()); // prints 42
}
公共异步任务DoSomethingWithUIAsync()
{
等待任务。延迟(100);
这个。Title=“你好!”;
返回42;
}
公共异步任务DoSomething()
{
var x=wait Application.Current.Dispatcher.Invoke(
DoSomethingWithUIAsync);
Debug.Print(x.ToString());//打印42
}
在这种情况下,接受一个
Func
参数并返回相应的
Task
,这是等待的。如果不需要从
DoSomethingWithUIAsync
返回任何内容,只需使用
Task
而不是
Task


或者,使用其中一种方法。

如何将参数传递到“DoSomethingWithUIAsync”?@Cabuxa.Mapache:
Dispatcher.Invoke(()=>DoSomethingWithUIAsync(param))@Noseratio当你思考为什么
等待调用(…)
有效时,很明显这正是你想要的。我只需要看到这个例子就可以“理解”它。谢谢您链接的关于Asyc最佳实践的特别好的MSDN文章。由于未使用ConfigureAwait(false),Debug.Print()调用不会也在UI线程上运行吗?为什么此答案被否决,有人能解释吗?接受的答案解释为:“[此表单]使用
Dispatcher.Invoke(操作回调)
重写
Dispatcher.Invoke
的表单,在这种特殊情况下,它接受
异步无效
lambda。这可能会导致非常意外的行为,就像在
异步无效
方法中通常发生的那样。“@JonathanGilbert这种非常意外的行为到底意味着什么?请提供一些代码。
async void
方法不会返回它已启动的任务(如果有)。调用方实际上甚至无法判断它是否是
异步的。如果您
Dispatcher.Invoke
a
Func
,则Dispatcher会识别此模式并观察
任务
,但如果您
Dispatcher.Invoke
一个
async void
,它实际上运行的是与同步方法相同的
Dispatcher.Invoke
async
实际上不是方法签名的一部分;它只是一个返回类型为
void
的方法。因此,它被视为一个同步方法;在本例中,异步lambda返回void并继承异步void方法的所有问题。一般来说,只有将异步lambda转换为返回任务的委托类型(例如Func)时,才应使用异步lambda。