Пометить функцию как асинхронную, но не ждать вызовов, есть какие-то проблемы? - PullRequest
3 голосов
/ 20 марта 2019

Есть ли побочные эффекты от наличия функции, помеченной как асинхронная, но на самом деле она не выполняет никаких ожидающих вызовов? Например:

public interface IMyInterface
{
    Task DoSomethingAsync();
}

public class DoSomething1:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        await getSomethingFromDatabaseAsync();
    }
}

public class DoSomething2:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        doSomethingElse();
    }
}

IMyInterface реализован несколькими классами, но для одного из классов нет вызовов await . Это вызовет какие-либо проблемы?

Ответы [ 4 ]

7 голосов
/ 20 марта 2019

В случае, если у вас есть метод интерфейса, который возвращает задачу, и у вас нет ожидающих (да, это происходит). Просто удалите ключевое слово async и верните Task.CompletedTask

Свойство Task.CompletedTask возвращает задачу, свойство Status которой установлено в RanToCompletion.

Получает задачу, которая уже успешно выполнена.

public class DoSomething2:IMyInterface
{
    public Task DoSomethingAsync()
    {
        doSomethingElse();
        return Task.CompletedTask;
    }
}

Да, есть побочные эффекты, компилятор подключает IAsyncStateMachine и создает кучу других IL , дополнительно будущие разработчики будут смотреть на ваш код с ire . Что касается других функциональных различий, я не могу думать о каких-либо от руки.

2 голосов
/ 23 марта 2019

IMyInterface реализован несколькими классами, но для одного из классов нет ожидающих вызовов.Это вызовет какие-то проблемы?

Я собираюсь проникнуть сюда на опасную территорию и не согласиться с Эриком Липпертом.В подавляющем большинстве случаев использование async без await действительно является ошибкой, и предупреждение компилятора полезно.Я бы сказал, что это действительно к северу от 90% времени.

Однако я бы сказал, что этот сценарий является исключением из этого правила.Проблема с простым отбрасыванием async / await заключается в том, что исключения обрабатываются совершенно по-разному:

public Task DoSomethingAsync()
{
  // if doSomethingElse throws, that exception is raised directly;
  // it is *not* captured and placed on the returned task!
  doSomethingElse();
  return Task.CompletedTask;
}

Ожидаемая семантика для метода Task -обращения заключается в том, что исключения захватываются и помещаются в возвращаемое значение.Task (ну, по крайней мере, не исключения с костью ).Чтобы сохранить эту семантику, вам нужно либо использовать async (и подавить предупреждение), либо явное try / catch:

#pragma warning disable 1998
public async Task DoSomethingAsync()
#pragma warning restore 1998
{
  doSomethingElse();
}

// or

public Task DoSomethingAsync()
{
  try
  {
    doSomethingElse();
    return Task.CompletedTask;
  }
  catch (Exception ex)
  {
    return Task.FromException(ex);
  }
}
0 голосов
/ 20 марта 2019

Методы, помеченные как асинхронные, будут работать так же, как это только создаст немного издержек, потому что, когда метод помечен как асинхронный компилятор, в основном генерирует конечный автомат для этого метода (который в вашем случае не будет использоваться в некоторых конкретных методах)

https://foreverframe.net/what-lies-beneath-asyncawait-in-c/

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

0 голосов
/ 20 марта 2019

В вашем случае, я думаю, что может быть проблема с блокировкой основного потока (и это зависит от того, волнует вас это или нет), и я думаю, что это не нужно разработчику.

Если у вас нет ожидающих звонков, вы можете сделать следующее, чтобы основной поток не был заблокирован (> .net 4.0):

public class DoSomething2:IMyInterface
{
     public async Task DoSomethingAsync()
     {
         await Task.Run(()=>doSomethingElse());
     }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...