Вопрос про асинки
От: SergASh  
Дата: 19.03.17 15:56
Оценка:
Привет всем.

Имеется следующий класс.
public static class Helper
{
  public static Task ExecuteInContextAsync( Func<IContext, Task> action )
  { // Вариант №1
    return ExecuteInDataContextAsync( context =>
                                      {
                                        action( context );
                                        return Task.FromResult( 0 );
                                      } );
  }

  public static async Task ExecuteInContextAsync( Func<IContext, Task> action )
  { // Вариант №2
    await ExecuteInDataContextAsync( async context =>
                                           {
                                             await action( context );
                                             return 0;
                                           } );
  }

  public static async Task<T> ExecuteInContextAsync<T>( Func<IContext, Task<T>> action )
  { // Полная реализация
    using ( IContext context = BuildContext() )
    {
      var result = await action( context );
      return result;
    }
  }

  private static IContext BuildContext()
  {
    return ...;
  }
}

public interface IContext : IDisposable
{
}

Полная реализация метода, которая Task<T> возвращает — длинная простыня в реальном коде.
Чтобы не повторяться, метод, который без возвращаемого значения, вызывает полную версию одним из двух приведенных способов.
Может кто-нибудь объяснить какая разница между этими двумя вариантами?

PS Понимаю, что варианта там не два может быть, а четыре, и что асинхронность делегата никак не связана с асинхронностью самого метода.
Re: Вопрос про асинки
От: Sinix  
Дата: 19.03.17 16:06
Оценка:
Здравствуйте, SergASh, Вы писали:

Не видя полного текста сказать сложно, но пока я вообще не вижу смысла во всех методах.
using (IContext context = BuildContext()) ... в клиентском коде и понеслась.

Если надо гарантированно очистить сontext(), то достаточно
  public static async Task<T> ExecuteInContextAsync<T>(Func<IContext, Task<T>> action)
  {
    using (IContext context = BuildContext())
    {
      return await action(context);
    }
  }

  public static async Task ExecuteInContextAsync<T>(Func<IContext, Task> action)
  { 
    using (IContext context = BuildContext())
    {
      await action(context);
    }
  }
Re: Вопрос про асинки
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.03.17 16:36
Оценка: 52 (2) +2
Здравствуйте, SergASh, Вы писали:

SAS>Полная реализация метода, которая Task<T> возвращает — длинная простыня в реальном коде.

SAS>Чтобы не повторяться, метод, который без возвращаемого значения, вызывает полную версию одним из двух приведенных способов.
SAS>Может кто-нибудь объяснить какая разница между этими двумя вариантами?

Первый вариант — засада. Он может даже не начать выполнение таска, который вернет action, не говоря уж о том, что дожидаться выполнения того таска не обязан. В итоге, таск может завершиться уже после освобождения контекста. Ну или попытаться.
Re[2]: Вопрос про асинки
От: SergASh  
Дата: 19.03.17 17:21
Оценка:
S>Первый вариант — засада. Он может даже не начать выполнение таска, который вернет action, не говоря уж о том, что дожидаться выполнения того таска не обязан. В итоге, таск может завершиться уже после освобождения контекста. Ну или попытаться.

Слона-то я не приметил С делегатом конечно неправильно было.
Тогда остается вопрос про сам метод. Где-то будет разница между такими вариантами?
  public static Task ExecuteInContextAsync( Func<IContext, Task> action )
  { // Вариант №1
    return ExecuteInDataContextAsync( async context =>
                                           {
                                             await action( context );
                                             return 0;
                                           } );
  }

  public static async Task ExecuteInContextAsync( Func<IContext, Task> action )
  { // Вариант №2
    await ExecuteInDataContextAsync( async context =>
                                           {
                                             await action( context );
                                             return 0;
                                           } );
  }
Re[2]: Вопрос про асинки
От: SergASh  
Дата: 19.03.17 17:26
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Не видя полного текста сказать сложно, но пока я вообще не вижу смысла во всех методах.

S>using (IContext context = BuildContext()) ... в клиентском коде и понеслась.

Я упростил конечно основной метод. Там ещё параметры есть, инициализация контекста, логи, обработка ошибок. Всего около 25 строк, которые вовсе не хочется повторять два раза.
К тому же то, как именно строится контекст, клиентскому коду лучше не показывать, а то вдруг кто-то захочет его сохранить куда-нибудь на подольще — и проблемы обеспечены.
Re[3]: Вопрос про асинки
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.03.17 17:34
Оценка: +1
Здравствуйте, SergASh, Вы писали:

S>>Первый вариант — засада. Он может даже не начать выполнение таска, который вернет action, не говоря уж о том, что дожидаться выполнения того таска не обязан. В итоге, таск может завершиться уже после освобождения контекста. Ну или попытаться.


SAS>Слона-то я не приметил С делегатом конечно неправильно было.

SAS>Тогда остается вопрос про сам метод. Где-то будет разница между такими вариантами?

Здесь мне хотелось бы верить, что разница с точки зрения наблюдаемого поведения не должна быть заметна. А разницу с точки зрения генерации компилятором автомата в случае async/await, не очень хочется обсуждать. Что еще... При отсутствии необходимости обработки исключений, using-ов, перечислителей и прочего, я бы предпочел метод, возвращающий чистый таск, т.е. без async/await.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.