Можно ли использовать ту же сигнатуру асинхронного метода в C# 5.0 и позже решить, как выполнять такой метод

Я хочу использовать последние асинхронные методы C# 5.0, но каким-то особым образом.

Рассмотрим следующий пример кода:

public abstract class SomeBaseProvider : ISomeProvider
{
   public abstract Task Process(SomeParameters parameters);    
}

public class SomeConcreteProvider1 : SomeBaseProvider 
{

   // in this method I want to minimize any overhead to create / run Task
   // NOTE: I remove here async from method signature, because basically I want to run 
   // method to run in sync!
   public override Task Process(SomeParameters parameters) {

      string result = "string which I don't need any async code to get";

      return Task.Run(() => result);
   }
}

public class SomeConcreteProvider2 : SomeBaseProvider 
{

   // in this method, it's OK for me to use async / await 
   public async override Task Process(SomeParameters parameters) {

      var data = await new WebClient().DownloadDataTaskAsync(urlToRequest);

      string result = // ... here we convert data byte[] to string some way

      return result;

   }
}

Теперь, как я собираюсь использовать асинхронные методы (вы можете игнорировать тот факт, что потребитель на самом деле приложение ASP.NET MVC4 в моем случае... это может быть что угодно):

public class SomeAsyncController : AsyncController
{

    public async Task SomethingAsync(string providerId)
    {
       // we just get here one of providers I define above
       var provider = SomeService.GetProvider(providerId);

       // we try to execute here Process method in async. 
       // However we might want to actually do it in sync instead, if  
       // provider is actually SomeConcreteProvider1 object.
       string result = await provider.Process(new SomeParameters(...));

       return Content(result);
     }
} 

Как вы можно увидеть, что у меня есть 2 реализации, каждая из которых будет работать по-разному: одну я хочу запускать в асинхронном режиме и не блокировать поток (SomeConcreteProvider2), а другую я хочу иметь возможность запускать синхронно и не создавать никаких объектов Task и т. д. ( который я не могу закодировать в коде выше, т.е. я создаю новую задачу здесь!).

Уже есть такие вопросы, как Как мне синхронно запустить асинхронный метод Task?. Однако я не хочу запускать что-то синхронно... Я хочу избежать каких-либо накладных расходов, если я знаю во время кода (т.е.перед выполнением), что некоторые реализации методов на самом деле НЕ будут асинхронными и им не нужно будет использовать какие-либо потоки / порты завершения ввода-вывода и т. д. Если вы проверите приведенный выше код, легко увидеть, что метод в SomeConcreteProvider1 в основном создает некоторую строку (html) , может сделать это очень быстро в том же потоке выполнения. Однако тот же метод в SomeConcreteProvider2 должен будет создать веб-запрос, получить веб-ответ и каким-то образом обработать его, и я действительно хочу сделать хотя бы веб-запрос в асинхронном режиме, чтобы избежать блокировки всего потока во время запроса (может быть на самом деле прекращено долгое время).

Итак, вопрос: как организовать мой код (разные сигнатуры методов или разные реализации, или?), чтобы иметь возможность решить, как выполнять метод, и избежать ЛЮБЫХ возможных накладных расходов, вызванных, например, Task.Run(... ) в методе SomeConcreteProvider1.Process?

Обновление 1: очевидные решения (некоторые из них я придумываю в процессе обсуждения), например, добавить какое-то статическое свойство к каждому из провайдеров (скажем, «isAsyncImplementation»), а затем проверить это свойство, чтобы решить, как для запуска метода (с ожиданием или без ожидания в действии контроллера) также есть некоторые накладные расходы: я хочу что-то лучше, если это возможно: D

6
задан Community 23 May 2017 в 12:25
поделиться