Недавно я вернулся к C# из страны Objective-C, и ключевые слова async/await в C# 5 выглядят круто. Но я все еще пытаюсь разобраться с правильным синтаксисом.
Я хочу объявить метод, который принимает асинхронный делегат в качестве параметра, но у меня возникают проблемы с правильным синтаксисом как вызывающего, так и вызываемого. Может ли кто-нибудь предоставить пример кода, показывающий объявление метода, вызов и вызов делегата?
Я думаю, что объявление будет примерно следующим. Обратите внимание, что эта функция не является асинхронной; то есть его асинхронность не зависит от делегата.
void DoSomethingWithCallback(async delegate foo(int))
{
...
foo(42);
...
}
Вызов будет примерно таким:
DoSomethingWithCallback(async (int x) => { this.SomeProperty = await SomeAsync(x); });
Конечно, ничего из этого не компилируется, и большинство примеров, которые я видел, предполагают, что у них есть поле или свойство, которое является делегатом, а не анонимным делегатом, который я хотел бы использовать.
Ответ 1 · рейтинг 84 · AndrewS
Функция, которая принимает делегат в качестве параметра, должна использовать именованный тип делегата; в отличие от Objective-C, вы не можете объявить анонимный тип делегата встроенным в определение функции. Однако дженерики Action‹> и Func‹> предоставляются, так что вам не нужно объявлять новый тип самостоятельно. В приведенном ниже коде я предполагаю, что делегат принимает один int в качестве параметра.
void DoSomethingWithCallback(Func<int,Task> callbackDelegate)
{
Task t = callbackDelegate(42);
}
Если эта функция на самом деле ничего не делает с возвращаемым объектом Task (как в коде, показанном выше), вы можете вместо этого использовать Action<int> в качестве типа делегата. Если вы используете действие, вы все равно можете объявить делегат асинхронным (ниже), но возвращаемый неявный объект Task игнорируется.
Синтаксис лямбда для вызова вышеуказанной функции прост, и синтаксис, который вы использовали в вопросе, верен. Обратите внимание, что здесь не нужно указывать тип параметра, так как его можно вывести:
DoSomethingWithCallback(async (intParam) => { this.myint = await Int2IntAsync(intParam); });
Вы также можете передать метод или переменную делегата, если хотите, вместо использования лямбда-синтаксиса:
async Task MyInt2Int(int p) { ... }
Func<int,Task> myDelegate;
void OtherMethod()
{
myDelegate = MyInt2Int;
DoSomethingWithCallback(myDelegate); // this ...
DoSomethingWithCallback(MyInt2Int); // ... or this.
}
Ответ 2 · рейтинг 9 · John Gietzen
Тип возвращаемого значения сигнатуры метода - Task, если тип возвращаемого значения отсутствует, или Task<T>, если тип возвращаемого значения есть.
Тем не менее, я не уверен на 100 %, что у вас могут быть такие асинхронные лямбда-выражения.
В методе, который использует задачу, вы должны либо "ожидать" задачу, либо использовать свойства и методы в задаче, чтобы получить результат.
Ответ 3 · рейтинг 8 · Dan
Если у меня есть задача, которую я хочу передать, но не выполнить, я могу обернуть задачу в Func<>, а затем вызвать эту Func<> для создания этой задачи. await можно использовать как обычно.
public class Example {
public Example(Func<Task> toBeExecutedInTheFuture)
{
FutureTask = toBeExecutedInTheFuture;
}
public async void ExecuteTaskExample()
{
await FutureTask();
// or alternatively
var myTask = FutureTask();
// do work
await myTask;
}
}