Подтвердить что ты не робот

Использование async/wait с Dispatcher.BeginInvoke()

У меня есть метод с некоторым кодом, который выполняет операцию await:

public async Task DoSomething()
{
    var x = await ...;
}

Мне нужен этот код для работы в потоке диспетчера. Теперь Dispatcher.BeginInvoke() ожидает, но я не могу отметить lambda как async, чтобы запустить await изнутри, например:

public async Task DoSomething()
{
    App.Current.Dispatcher.BeginInvoke(async () =>
        {
            var x = await ...;
        }
    );
}

Во внутренней async, я получаю ошибку:

Невозможно преобразовать лямбда-выражение для ввода "System.Delegate", потому что это не тип делегата.

Как я могу работать с async из Dispatcher.BeginInvoke()?

4b9b3361

Ответ 1

другой ответ, возможно, ввел неясную ошибку. Этот код:

public async Task DoSomething()
{
    App.Current.Dispatcher.Invoke(async () =>
    {
        var x = await ...;
    });
}

использует Dispatcher.Invoke(Action callback) форму переопределения Dispatcher.Invoke, которая принимает в этом конкретном случае async void лямбда. Это может привести к совершенно неожиданному поведению, как это обычно бывает с async void методами.

Вероятно, вы ищете что-то вроде этого:

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
}

В этом случае Dispatch.Invoke<Task<int>> принимает аргумент Func<Task<int>> и возвращает соответствующий Task<int>, который является ожидаемым. Если вам не нужно ничего возвращать из DoSomethingWithUIAsync, просто используйте Task вместо Task<int>.

В качестве альтернативы используйте один из методов Dispatcher.InvokeAsync.

Ответ 2

Используйте Dispatcher.Invoke()

public async Task DoSomething()
{
    App.Current.Dispatcher.Invoke(async () =>
    {
        var x = await ...;
    });
}