Как я могу ожидать async-метода без модификатора async в этом родительском методе?
У меня есть метод, который я хочу ждать, но я не хочу вызывать эффект домино, который может вызвать вызов этого метода вызова и ждать его. Например, у меня есть этот метод:
public bool Save(string data)
{
int rowsAffected = await UpdateDataAsync(data);
return rowsAffected > 0;
}
Я зову:
public Task<int> UpdateDataAsync()
{
return Task.Run(() =>
{
return Data.Update(); //return an integer of rowsAffected
}
}
Это не сработает, потому что я должен поставить "async" в сигнатуру метода для Save()
а затем я не могу вернуть bool
я должен сделать это Task<bool>
но я не хочу, чтобы кто-то ожидал Save()
метод.
Есть ли способ приостановить выполнение кода, например, ждать или как-то ждать этого кода без модификатора async?
Ответы
Ответ 1
Как я могу ожидать async-метода без модификатора async в этом родительском методе?
Это похоже на вопрос: "Как я могу написать приложение с помощью С#, но не зависеть от какой-либо среды выполнения.NET?"
Короткий ответ: не делайте этого.
Действительно, то, что вы делаете здесь, - это естественный синхронный метод (Update
), что делает его асинхронным, запустив его в потоке пула потоков (UpdateDataAsync
), а затем вы хотите заблокировать его, чтобы сделать асинхронный метод появляются синхронно (Save
). Серьезные красные флаги.
Я рекомендую вам внимательно изучить знаменитую пару сообщений в блоге Стивена Тууба, чтобы я открывал асинхронные обертки для своих синхронных методов и должен ли я открывать синхронные обертки для моих асинхронных методов. Ответ на оба вопроса - "нет", хотя Стивен Тууб объясняет несколько вариантов сделать это, если вам действительно нужно.
Это "действительно нужно" следует зарезервировать для уровня приложения. Я предполагаю, что эти методы (Update
, UpdateDataAsync
и Save
) находятся в разных слоях приложения (например, данные/служба данных/модель представления). Уровни службы данных/данных не должны выполнять синхронные/асинхронные преобразования. Модель представления (специфичный для приложения) является единственной, у которой есть оправдание для такого преобразования - и она должна делать это только в крайнем случае.
Ответ 2
Изменение: этот ответ был до Task.Run добавлен. С этим дополнительным контекстом сценарий лучше всего описывается как "не делай этого".
Вы можете получить доступ. .Result
или использовать .Wait()
, но вам нужно знать, как задача выполняется в первую очередь. В частности, вам нужно знать, использует ли он синхронный контекст. Причина, по которой это важно, заключается в том, что если это произойдет, это может зайти в тупик немедленно, потому что некоторым контекстам синхронизации необходимо, чтобы вызывающий контекст полностью вышел (например, MVC sync-context должен оставить метод действия контроллера).
Для защиты от этого сложно, но вы, вероятно, должны всегда явно указывать таймаут с вызовом на .Wait()
- на всякий случай.