2013-10-24 2 views
0

В моем приложении NET 4.5 у меня есть служебный уровень.Обработать выполнение класса в асинхронном режиме

Я использую диспетчер посылать запросы и получать ответы:

Примера: GetPostByIdQuery обрабатывается GetPostByIdHandler и возвращает GetPostByIdReply.

Как я могу изменить свой код, чтобы запрос обрабатывался асинхронно?

public class Dispatcher : IDispatcher { 

    public TReply Send<TReply>(Query query) where TReply : Reply, new() { 

    Type type = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TReply)); 

    IQueryHandler handler = (IQueryHandler)ObjectFactory.GetInstance(type); 

    try { 

     return (TReply)handler.Handle(query); 

    } catch (Exception exception) { 

     ILogger logger = ObjectFactory.GetInstance<ILogger>(); 
     logger.Send(exception); 
     if (Debugger.IsAttached) throw; 
     return new TReply { Exception = exception }; 

    } 
    } // Send 
} 

UPDATE: Учитывая предложение я добавил:

public interface IDispatcher { 

    TReply Send<TReply>(Query query) where TReply : Reply, new(); 
    Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new(); 

} // IDispatcher 

public class Dispatcher : IDispatcher { 

    public TReply Send<TReply>(Query query) where TReply : Reply, new() { 
    } // Send 

    public Task<TReply> Send<TReply>(Query query) where TReply : Reply, new() { 
    } // Send 

} 

ДВА ВОПРОСА:

  1. мне нужно повторить свой код в обоих Отправить методы ли? Или можно позвонить другому?

  2. Вместо двух методов отправки можно ли использовать один метод с логическим «sendAsync»? Я не уверен, если это имеет смысл, поскольку возвращаемый тип будет то же самое ...

+2

Изменить интерфейс для возврата 'Задача ' – SLaks

+0

Какая у вас конкретная проблема? Почему ваш случай отличается от любого другого метода async? – usr

+0

Так что мне нужно только добавить задачу к моему интерфейсу и методу моего класса?Я спросил это, потому что моя идея состояла в том, чтобы иметь что-то вроде: TReply Отправить (Запрос запроса, Boolean async = false) ... Таким образом, я бы решил, когда использовать asyn или нет. Разве это не может быть сделано? –

ответ

2

Если вы хотите «Embrace async» и получить какую-либо реальную выгоду от этого, вам нужно будет изменить IQueryHandler и сделать это асинхронным, так как именно здесь выполняется настоящая работа.

Вы никогда не показал нам, что делает IQueryHandler, но вы, вероятно, нужно будет писать новые методы, чтобы действительно поддерживать ASync код

public class Dispatcher : IDispatcher { 

    public TReply Send<TReply>(Query query) where TReply : Reply, new() { 
     //(Snip) No changes to the original code 
    } // Send 

    public async Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new() { 

    Type type = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TReply)); 

    IQueryHandler handler = (IQueryHandler)ObjectFactory.GetInstance(type); 

    try { 

     return await (TReply)handler.HandleAsync(query); //Uses the new method "Task<TResult> IQueryHandler<TQueryType, TResult>.HandleAsync(TQueryType query)" 

    } catch (Exception exception) { 

     ILogger logger = ObjectFactory.GetInstance<ILogger>(); 
     logger.Send(exception); 
     if (Debugger.IsAttached) throw; 
     return new TReply { Exception = exception }; 

    } 
    } // Send 
} 

Если вы не заботитесь о улучшения производительности написания кода реального асинхронной (это может не стоит стоимость обновления всех ваших IQueryHandler с), но вы все еще хотите Подходят использования асинхр/ждут медленного процесса вы можете сделать легкую обертку, делая

public class Dispatcher : IDispatcher { 

    public TReply Send<TReply>(Query query) where TReply : Reply, new() { 
     //(Snip) No changes to the original code 
    } // Send 

    public Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new() { 
     return Task.Run(() => Send<TReply>(query)); 
    } // SendAsync 
} 

Однако, как я уже говорил, дон ожидать больших результатов g Из-за этого вам просто не нужно делать это самостоятельно (и, возможно, некоторое время в будущем вы могли бы заменить это реальным асинхронным кодом без необходимости обновления каких-либо вызывающих абонентов, которые используют эту функцию).

0

Вы можете добавить новый метод SendAsync как таковой:

public Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new() 
{ 
    return Task.Run(() => 
    { 
     return Send<TReply>(query); 
    }); 
} 

Чтобы ответить на ваш второй вопрос, если вы хотите только выставить метод подписи, как Send(Query query, bool sendAsync), и сделать свой оригинальный метод Send частный, вы могли бы написать что-то вроде этого:

public dynamic Send<TReply>(Query query, bool sendAsync) where TReply : Reply, new() 
{ 
    if (sendAsync) 
    { 
     return Task.Run(() => 
     { 
      return Send<TReply>(query); 
     } 
    } 
    else 
    { 
     return Send<TReply>(query); 
    } 
} 

Аналогично, Object может быть возвращен и распакован вызывающим абонентом. Но писать это так довольно уродливо; Я просто указываю, что это возможно.

+1

Это асинхронно только в том смысле, что это происходит в фоновом режиме - первоочередные причины, по которым люди, такие как асинхрон, не здесь. Обертка синхронного метода в Task.Run() на уровне API - это плохая идея, потому что она скрывает неэффективность от пользователя, который в противном случае мог бы лучше обойти синхронный вызов. –

+1

Вместо «dynamic» я бы просто выполнил [Task.FromResult] (http://msdn.microsoft.com/en-us/library/hh194922.aspx) и возвратил 'Task ' как для синхронизации, так и для асинхронная версия. –

Смежные вопросы