2017-01-14 4 views
1

Следующий код не компилировать:C# Прогресс Отчетность

async Task Foo (Action<int> onProgressPercentChanged) 
{ 
    return Task.Run (() => 
    { 
     for (int i = 0; i < 1000; i++) 
     { 
      if (i % 10 == 0) onProgressPercentChanged (i/10); 

     } 
    }); 
} 

из-за следующей ошибки:

Тяжесть Код Описание проекта Строка файла Подавление Государственный CS1997 Ошибка С «Nutshell.Foo (Action)» это асинхронный метод, который возвращает «Задача», ключевое слово return не должно сопровождаться выражением объекта. Вы намеревались вернуть «Задачу»?

, но это делается точно так, как показано в книге. Есть что-то, что мне не хватает?

ответ

2

Вместо return вы должны await вашего Task.Run заявления

async Task Foo(Action<int> action) 
{ 
    await Task.Run(() => /*...*/); 
} 

или, если вы предпочитаете, чтобы вернуться Task, вы не должны пометить метод как async

Task Foo(Action<int> action) 
{ 
    return Task.Run(() => /*...*/); 
} 
+0

Спасибо, tdragon, попробовал, и это сработало. Обычно, когда код, который не будет компилироваться, иллюстрируется в книге, указывается, что он не будет. На этот раз это не так. – AndrewH

1

Удалить инструкция по применению. Ваш метод не должен возвращать ничего.

+0

Лучше удалить 'async' перед методом. –

4

Вашего метод отмечен async Task, поэтому компилятор ожидает, что он ничего не вернет. Если вы хотите вернуть задачу, то вы не должны отмечать метод async. Кроме того, вы можете использовать await внутри метода async.

// Option 1 
Task Foo (Action<int> onProgressPercentChanged) 
{ 
    return Task.Run (() => 
    { 
    for (int i = 0; i < 1000; i++) 
    { 
     if (i % 10 == 0) onProgressPercentChanged (i/10); 
    } 
    }); 
} 

// Option 2 
async Task Foo (Action<int> onProgressPercentChanged) 
{ 
    await Task.Run (() => 
    { 
    for (int i = 0; i < 1000; i++) 
    { 
     if (i % 10 == 0) onProgressPercentChanged (i/10); 
    } 
    }); 
} 

Более подробную информацию о разнице между этими двумя, см мой пост в блоге на eliding async.

к другим проблемам ...

Использование отчетности, встроенных в .NET, а не свертывать свой собственный прогресс.

.NET использует IProgress<T> тип, так что вы можете использовать это:

Следуя конвенции прогресса, мы позволяем звонящие к не запросу прогресс обновления, и мы также позволяют очень естественно сортировочная в потоке пользовательского интерфейса с использованием Progress<T>:

// Caller, from UI thread 
var progress = new Progress<int>(report => 
{ 
    // Handle progress report. This code is already on the UI thread! :) 
}); 
await Foo(progress); 

не используйте Task.Run в реализации; используйте метод Task.Run для вызова метода.Using Task.Run to implement fake-asynchronous methods is an antipattern. Я также пишу об этом on my blog.

Применяя это исправление делает Foo синхронные, который совсем правильно, так как он не делает никакого фактического асинхронной работы:

void Foo(IProgress<int> progress = null) 
{ 
    for (int i = 0; i < 1000; i++) 
    { 
    if (progress != null && i % 10 == 0) progress.Report(i/10); 
    } 
} 

// Caller 
var progress = new Progress<int>(report => ...); 
await Task.Run(() => Foo(progress)); 

И, наконец, не дроссельных отчеты о ходе работы на источнике; дросселируйте их на приемнике. Если ваш код когда-либо работает на разных процессорах, то любое дросселирование, которое вы выполняете в источнике (i % 10), будет проблематичным.Лучше использовать реализацию IProgress<T>, которая дросселирует.

Это хорошо упрощает код:

void Foo(IProgress<int> progress = null) 
{ 
    for (int i = 0; i < 1000; i++) 
    { 
    if (progress != null) progress.Report(i/10); 
    } 
} 
Смежные вопросы