2014-04-23 13 views
5

Tại sao task chờ đợi mãi mãi ?:IObservable <T> .ToTask <T> phương thức trả về nhiệm vụ đang chờ kích hoạt

var task = Observable 
    .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved") 
    .Where(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName) 
    .Select(i => i.EventArgs) 
    .RunAsync(System.Threading.CancellationToken.None) 
    .ToTask(); 

task.Wait(); 

Tôi biết "PushMessageRecieved" là bắn; Tôi có thể thiết lập một điểm break trên Select lambda và nhấn nó. Nhưng task.Wait() không bao giờ di chuyển. Cập nhật

tốt hơn:FirstAsync() là những gì tôi đang tìm kiếm:

public static Task<MessageResponseEventArgs> HandlePushMessageRecievedAsync(this ICommunicator communicator, RequestName requestName) 
    { 
     if (communicator == null) return Task.FromResult<MessageResponseEventArgs>(null); 

     var observable = GetCommunicatorObservableForPushMessageReceived(communicator); 
     return observable 
      .Where(i => i.GetRequestFromReceivedMessage().Name == requestName) 
      .Select(i => i) 
      .FirstAsync() 
      .ToTask(); 
    } 

nơi GetCommunicatorObservableForPushMessageReceived() là:

static IObservable<MessageResponseEventArgs> GetCommunicatorObservableForPushMessageReceived(ICommunicator communicator) 
    { 
     if (communicatorObservableForPushMessageReceived == null) 
     { 
      communicatorObservableForPushMessageReceived = Observable 
       .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved") 
       .Where(i => !IsPreviousMessage(i.EventArgs.GetRequestFromReceivedMessage().EventId)) 
       .Select(i => i.EventArgs); 
     } 

     return communicatorObservableForPushMessageReceived; 
    } 

Cập nhật: gì là hơi khủng khiếp là thế này (nhưng nó hoạt động) :

public static Task<MessageResponseEventArgs> HandlePushMessageRecievedAsync(this ICommunicator communicator, RequestName requestName) 
{ 
    if (communicator == null) return Task.FromResult<MessageResponseEventArgs>(null); 

    var completionSource = new TaskCompletionSource<MessageResponseEventArgs>(); 

    Observable 
     .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved") 
     .Where(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName) 
     .Select(i => i.EventArgs) 
     .ToEvent().OnNext += (args) => 
     { 
      if (args.Response.Errors != null && args.Response.Errors.Any()) 
      { 
       completionSource.TrySetException(args.Response.Errors.Select(j => new Exception(j.ErrorMessage))); 
      } 
      else 
      { 
       completionSource.TrySetResult(args); 
      } 
     }; 

    return completionSource.Task; 
} 
+0

Liệu các 'Name' trận đấu bất động sản' requestName'? – Lee

+0

@Lee: Nếu nó chạm vào 'Select' lambda, như OP nói, thì có, nó phải khớp với mệnh đề Where. – StriplingWarrior

+1

Không nên ToTask xảy ra trước RunAsync? –

Trả lời

8

Cả hai RunAsyncToTask sản lượng giá trị cuối cùng có thể quan sát được. Do đó, không có giá trị nào được tạo cho đến khi có thể quan sát được hoàn thành. Nhưng các quan sát được tạo ra với FromEventPattern thường không hoàn thành. Bạn cần buộc họ hoàn thành một số thứ như Take hoặc Until.

Tôi cũng sẽ lưu ý rằng RunAsyncToTask về bản chất là không cần thiết và không cần phải thực hiện cả hai.

Trong trường hợp của bạn, tôi sẽ giả sử bạn đang thực sự quan tâm đến các giá trị đầu tiên mà làm cho nó thông qua bộ lọc của bạn:

var task = Observable 
    .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved") 
    .FirstAsync(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName) 
    .Select(i => i.EventArgs) 
    .ToTask(); 

task.Wait(); 
+0

Đánh giá cao! Công việc này: 'Chọn (i => i) .Take (1).ToTask() ' – rasx

+0

Điều này thậm chí còn tốt hơn:' Chọn (i => i) .FirstAsync(). ToTask() ' – rasx

+1

Tại sao bạn tiếp tục thêm' Chọn (i => i) '? Điều đó không phục vụ mục đích nào. – Brandon

2

Các trình xử lý cho sự kiện PushMessageRecieved mà bạn đang quan sát cần được chạy trên luồng giao diện người dùng, trong bối cảnh đồng bộ hóa hiện tại. Bạn đang chặn chuỗi giao diện người dùng (đại diện cho ngữ cảnh hiện tại) trong khi bạn đợi tác vụ này. Nhiệm vụ không thể hoàn thành bởi vì bạn đang chờ đợi nó, bạn sẽ không bao giờ kết thúc chờ đợi vì nó không thể chạy. Deadlock.

Bạn không nên đồng bộ chặn trên tác vụ mà thực thi mã không đồng bộ như là sự tiếp tục của tác vụ đó.

+0

Tôi đánh giá cao những gì bạn đang nói nhưng sẽ phải áp dụng lời khuyên này cho trường hợp kiểm tra đơn vị: không có chuỗi giao diện người dùng. – rasx

+1

@rasx Trước hết, bạn nên chắc chắn rằng không có bối cảnh đồng bộ hóa trong thử nghiệm đơn vị của bạn; cũng có thể là một. Và nếu không có ** thì sẽ có ** bởi vì nếu không bạn không thích hợp với môi trường thực của bạn. – Servy

Các vấn đề liên quan