Реализовать асинхронный интерфейс с синхронным кодом - PullRequest
0 голосов
/ 22 июня 2019

У меня есть простой набор кода, в котором я пытаюсь реализовать интерфейс с асинхронным методом. Реализации до сих пор были теми вещами, которые используют асинхронную часть этого и заканчивают тем, что ожидали вещи. Однако эта новая реализация интерфейса представляет собой простую синхронную операцию - не нужно ждать.

Когда я это реализую, в первую очередь я чувствую себя странно. Во-вторых, Visual Studio подтверждает мое неудобство предупреждением о том, что метод будет работать синхронно, чего я и ожидал, но предупреждение говорит о том, что для VS он тоже пахнет плохо. Есть ли лучший шаблон, которому я должен следовать?

public interface IActivity
{
    async Task<bool> DoStuff();
}

//...

List<IActivity> activities = new List<IActivity>(){
   new SynchronousActivityA(),
   new SynchronousActivityB(),
   new AsynchronousActivityC()
};

foreach (var activity in activities){
    bool stuff = await activity.DoStuff();
    //do things with stuff.
}

Я мог бы просто заставить мою реализацию DoStuff () сделать что-то вроде этого:

await Task.Run(() => DoStuffSynchronously());

Это заставило бы мое предупреждение исчезнуть и почувствовать себя немного более "правильным", но я не уверен, какую пользу это принесло бы по сравнению с написанием реализации DoStuff (), как если бы это была синхронная подпись.

1 Ответ

2 голосов
/ 22 июня 2019

интерфейс с асинхронным методом

Технически, «метод, который возвращает Task<T>». async и await являются подробностями реализации.

Метод, возвращающий ожидаемое, - это метод, который может быть асинхронным. Синхронный возврат выполненного задания вполне приемлем.

Один из способов сделать это - использовать Task.FromResult, но вы также должны быть уверены, что захватили исключения и вернули их также в задаче:

try { return Task.FromResult(DoStuffSynchronously()); }
catch (Exception ex) { return Task.FromException<bool>(ex); }

Это немного многословно. По сути, это то же самое, что и async без await, но вам нужно #pragma убрать предупреждение, что также неудобно. Если вы делаете это часто, вы можете определить для него служебный метод, например, TaskHelper.ExecuteAsTask в моей библиотеке AsyncEx .

Не следует использовать Task.Run только для того, чтобы «сделать код асинхронным». Task.Run использует поток пула потоков, который в этом случае не нужен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...