2011-10-09 26 views
18

Nếu tôi có quyền truy cập vào một IObservable mà tôi biết chỉ bao giờ sẽ trở lại một mặt hàng, sẽ làm việc này và nó là mô hình sử dụng tốt nhất?Reactive Quan sát Subscription Xử

IDisposable disposable = null; 
disposable = myObservable.Subscribe(x => 
    { 
    DoThingWithItem(x); 
    if (disposable != null) 
    { 
     disposable.Dispose(); 
    } 
    }); 
+1

IMHO thực tế là một đối tượng xử lý là trong phạm vi làm cho nó một phong cách xấu. Tui bỏ lỡ điều gì vậy? –

+0

Bằng cách này, bạn có nghĩa là biến "dùng một lần" có thể được xử lý nếu cháy MyObservable trước khi biến dùng một lần đi ra khỏi phạm vi? Một mô hình tốt hơn để xử lý đối tượng này là gì? – Noob

Trả lời

9

Tuyên bố từ chối trách nhiệm: Tôi vẫn đang học Rx. Vì vậy, tôi không thực sự là một chuyên gia nhưng tôi tin rằng dùng một lần được trả về bởi Subscribe sẽ chỉ ngừng đăng ký thuê bao. Ngoài ra nếu nguồn hoàn thành, như trong trường hợp của bạn, việc hủy đăng ký được thực hiện tự động. Vì vậy, tôi nghĩ rằng Dispose có dư thừa và có thể được xóa an toàn.

Xem câu trả lời cho question này cho biết thêm.

4

Chức năng Take sẽ làm chính xác những gì bạn đang tìm kiếm. Trong trường hợp này, Take(1).

+2

Những gì bạn nói có thể được chứng minh? –

46

Phương tiện mở rộng được trả về bằng phương pháp mở rộng Subscribe chỉ được trả lại để cho phép bạn hủy đăng ký theo cách thủ công từ quan sát trước kết thúc tự nhiên có thể quan sát được.

Nếu có thể quan sát được - với OnCompleted hoặc OnError - thì đăng ký đã được xử lý cho bạn.

Hãy thử mã này:

var xs = Observable.Create<int>(o => 
{ 
    var d = Observable.Return(1).Subscribe(o); 
    return Disposable.Create(() => 
    { 
     Console.WriteLine("Disposed!"); 
     d.Dispose(); 
    }); 
}); 

var subscription = xs.Subscribe(x => Console.WriteLine(x)); 

Nếu bạn chạy ở trên, bạn sẽ thấy rằng "xử lý!" được ghi vào bàn điều khiển khi có thể quan sát được mà không cần bạn gọi số .Dispose() khi đăng ký.

Một điều quan trọng cần lưu ý: các bộ thu rác không bao giờ gọi .Dispose() trên đăng ký quan sát được, vì vậy bạn phải vút của đăng ký của bạn nếu họ không có (hoặc không có) đã kết thúc một cách tự nhiên trước khi thuê bao của bạn đi ra khỏi phạm vi.

Đi này, ví dụ:

var wc = new WebClient(); 

var ds = Observable 
    .FromEventPattern< 
     DownloadStringCompletedEventHandler, 
     DownloadStringCompletedEventArgs>(
      h => wc.DownloadStringCompleted += h, 
      h => wc.DownloadStringCompleted -= h); 

var subscription = 
    ds.Subscribe(d => 
     Console.WriteLine(d.EventArgs.Result)); 

Các ds thể quan sát được sẽ chỉ gắn với xử lý sự kiện khi nó có một thuê bao và sẽ chỉ tách khi chạy xong quan sát hoặc đăng ký sẽ được xử lý. Vì nó là một trình xử lý sự kiện quan sát được sẽ không bao giờ hoàn toàn bởi vì nó đang chờ đợi sự kiện hơn, và do đó xử lý là cách duy nhất để tách từ sự kiện này (đối với ví dụ trên).

Khi bạn có một FromEventPattern thể quan sát được mà bạn biết sẽ chỉ bao giờ trả lại một giá trị thì nó là khôn ngoan để thêm phương pháp .Take(1) phần mở rộng trước khi đăng ký để cho phép xử lý sự kiện để tự động tách và sau đó bạn không cần phải tự định đoạt đăng ký.

Giống như vậy:

var ds = Observable 
    .FromEventPattern< 
     DownloadStringCompletedEventHandler, 
     DownloadStringCompletedEventArgs>(
      h => wc.DownloadStringCompleted += h, 
      h => wc.DownloadStringCompleted -= h) 
    .Take(1); 

Tôi hy vọng điều này sẽ giúp.

+0

Cảm ơn! Tôi có vấn đề chính xác này (một sự kiện mà tôi chỉ muốn một trong số đó), và 'Take (1)' là giải pháp hoàn hảo. – moswald

+2

@moswald Lưu ý 'FirstAsync()' thực hiện điều tương tự. – lobsterism

+1

'bộ thu gom rác không bao giờ gọi .Dispose() trên các mục đăng ký quan sát được - Đây là những gì tôi đã ở đây. Cảm ơn! –

0

Ngược lại với một số ý kiến ​​nó không phải ở tất cả các bất thường để xử lý một thuê bao từ bên OnNext.

Trong khi đó là sự thật mà xử lý tại OnCompletedOnError được thực hiện cho bạn bởi một thuê bao bọc rằng phương pháp Subscribe mở rộng tạo ra, bạn có thể muốn huỷ đăng ký dựa trên một giá trị mà bạn đang quan sát (như trong trường hợp của bạn: Ai là 1) . Bạn không phải luôn luôn có một quan sát được biết là chỉ tạo ra một giá trị.

Vấn đề là bạn chỉ nhận được IDisposable sau khi đã đăng ký. Một quan sát có thể gọi lại cho bạn trên OnNext ngay cả trước khi nó trả lại cho bạn số IDisposable để hủy đăng ký (tùy thuộc vào những thứ như IScheduler sử dụng).

System.Reactive.Disposables.SingleAssignmentDisposable có ích trong trường hợp này. Nó kết thúc tốt đẹp một số IDisposable mà bạn có thể chỉ định trễ và sẽ ngay lập tức bỏ nó khi chuyển nhượng nếu SingleAssignmentDisposable đã được xử lý trước đó. Ngoài ra, nó còn mang một thuộc tính IsDisposed, ban đầu là false và được đặt thành true khi gọi Dispose().

Vì vậy:

IObservable<string> source = ...; 

var subscription = new SingleAssignmentDisposable(); 
subscription.Disposable = source.Subscribe(x => 
{ 
    if (subscription.IsDisposed) // getting notified though I've told it to stop 
     return; 
    DoThingsWithItem(x); 
    if (x == "the last item I'm interested in") 
     subscription.Dispose(); 
}); 
Các vấn đề liên quan