2014-02-15 1 views
2

У меня есть вид автобуса, который реализует этот интерфейс:создать метод асинхронной, который оборачивает подписаться и публиковать на автобусе

public interface IBus 
{ 
    void Publish<T>(T t); 
    void Subscribe<T>(Guid subscriptionId, Action<T> action); 
    void Unsubscribe<T>(Guid subscriptionId); 
} 

Вот пример того, как я использую его:

public void PrintName() 
{ 
    IBus bus = new Bus(); 
    var id = Guid.NewGuid(); 
    bus.Subscribe<ReplyUserName>(id, replyUserName => 
    { 
     bus.Unsubscribe<ReplyUserName>(id); 
     Console.WriteLine(replyUserName.UserName); 
    }); 

    Bus.Publish(new RequestUserName()); 
} 

а вот RequestUserName и ReplyUserName классы:

public class RequestUserName {} 

public class ReplyUserName 
{ 
    public string UserName { get; set; } 
} 

Однако я хотел бы написать метод расширения, обернул бы это с асинхронном:

public static class BusExtension 
{ 
    public static async Task<TResult> Request<TRequest, TResult>(this IBus bus, TRequest request) 
    { 
     // TODO... 
    } 
} 

Так что я буду иметь возможность написать предыдущий код таким образом:

public async void PrintName() 
{ 
    IBus bus = new Bus(); 
    var replyUserName = await bus.Request<RequestUserName, ReplyUserName>(new RequestUserName()); 
    Console.WriteLine(replyUserName.UserName); 
} 

что я должен написать вместо TODO?

ответ

5

TaskCompletionSource<T>wrap anything в await-совместимый метод.

public static Task<TResult> Request<TRequest, TResult>(this IBus bus, TRequest request) 
{ 
    var tcs = new TaskCompletionSource<TResult>(); 
    var id = Guid.NewGuid(); 
    bus.Subscribe<TResult>(id, result => 
    { 
    bus.Unsubscribe<TResult>(id); 
    tcs.TrySetResult(result); 
    }); 
    bus.Publish(request); 
    return tcs.Task; 
} 

Заметим, однако, что вы должны ensure that the task is completed. Если есть вероятность, что шина не ответит на запрос, у вас должен быть таймер или что-то, что вызывает ошибку TaskCompletionSource.

+0

Что произойдет, если объект TaskCompletionSource никогда не будет неисправен? – Alon

+0

Предполагая, что у вас есть какой-то код, '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' –

+0

Спасибо, ты мне очень помог. – Alon

4

Вы могли бы реализовать это следующим образом:

var taskCompletionSource = new TaskCompletionSource<TResult>(); 
bus.Subscribe<TResult>(id, result => 
{ 
    bus.Unsubscribe<TResult>(id); 
    taskCompletionSource.SetResult(result); 
}); 
bus.Publish(request); 
return taskCompletionSource.Task; 

Вы также можете проверить Reactive Extensions (Rx), как ваш интерфейс IBus похож на интерфейс ISubject (http://msdn.microsoft.com/en-us/library/hh211669.aspx). Библиотека Reactive Extensions уже предоставляет удобные методы расширения, аналогичные тем, которые вы пытаетесь реализовать.

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