2012-01-17 13 views
6

Tôi đang sử dụng Tiện ích mở rộng phản ứng để xử lý sự kiện dễ dàng trong ViewModels của tôi (ứng dụng Silverlight và/hoặc Wp7). Vì lợi ích của sự đơn giản hãy nói rằng tôi có một dòng như thế này trong ctor của VM của tôi:Làm gì với IObservers đang được xử lý?

Observable.FromEvent<PropertyChangedEventArgs>(
          h => MyObject.PropertyChanged += h, 
          h => MyObject.PropertyChanged -= h) 
    .Where(e=>e.PropertyName == "Title") 
    .Throttle(TimeSpan.FromSeconds(0.5)) 
    .Subscribe(e=>{/*do something*/}); 

này trả về một đối tượng IDisposable, mà nếu xử lý sẽ huỷ đăng ký.(Tôi có đúng trong giả định này không?)
Nếu tôi không có tham chiếu đến nó, sớm hay muộn nó sẽ được thu thập và người xử lý của tôi sẽ bị hủy đăng ký.

Tôi thường có một List<IDisposable> trong VM của mình và tôi thêm đăng ký vào nó, nhưng tôi cảm thấy dơ bẩn về nó, như thể tôi không làm điều gì đó theo cách Rx chính xác.

Thực tiễn tốt nhất, mẫu được đề xuất trong các tình huống như thế này là gì?

Trả lời

9

Giả định đầu tiên của bạn là chính xác, IDisposable là để hủy đăng ký. Tuy nhiên, bạn không cần phải giữ một tham chiếu đến IDisposable để ngăn không cho người quan sát của bạn được thu thập. Các IObservable sẽ cần phải giữ một tham chiếu đến người quan sát để có thể gọi phương pháp của nó, do đó giữ cho người quan sát còn sống miễn là các quan sát là còn sống.

Người đọc sắc sảo sẽ nhận ra rằng tôi phần nào đang cầu xin câu hỏi, bởi vì tôi đã giả định rằng các quan sát sẽ không được thu thập. Để giải quyết vấn đề đó, chúng ta hãy thực hiện một số phỏng đoán hợp lý về những gì đang diễn ra đằng sau hậu trường. Quan sát đầu tiên là đăng ký một sự kiện. Điều này có nghĩa là đối tượng có sự kiện có liên quan đến người quan sát của chúng tôi kể từ thời điểm chúng tôi đăng ký thời gian chúng tôi hủy đăng ký. Vì các nhà khai thác Rx phải đăng ký nguồn của họ, người ta có thể giả định rằng người quan sát sự kiện có tham chiếu đến Người quan sát ở đâu, có tham chiếu đến người quan sát Throttle, mà tất nhiên là ám chỉ người quan sát cuối cùng của chúng tôi.

Vì chúng tôi không giữ cách nào để hủy đăng ký, điều này liên kết cuộc sống của người quan sát với cuộc sống của đối tượng với sự kiện. Nếu không có kiến ​​thức đầy đủ về chương trình của bạn, đó là tất cả các chuỗi xa hơn tôi có thể đi, nhưng tôi nghĩ rằng nó phải là đủ để bạn có thể xác định tuổi thọ của các quan sát được.

Điều này thực sự chỉ ra một "rò rỉ bộ nhớ" tiềm ẩn mà bạn có thể có với các sự kiện .NET chuẩn, các đối tượng giữ tất cả người đăng ký sự kiện của họ còn sống, dẫn đến câu hỏi thứ hai của bạn. Nếu bạn không giữ một tham chiếu đến IDisposable, bạn sẽ không bao giờ có thể hủy đăng ký khỏi sự kiện và đối tượng của bạn sẽ tiếp tục nhận được thông báo, ngay cả sau khi bạn đóng chế độ xem nó có liên quan đến. Nếu nguồn sự kiện không tồn tại lâu hơn chế độ xem, điều này có thể không phải là vấn đề, nhưng Tôi khuyên bạn nên sử dụng dùng một lần.

Không có gì là "un-Rx" về điều này và Rx thậm chí còn bao gồm một lớp học hay để sử dụng làm phương án thay thế cho Danh sách nếu bạn muốn, System.Reactive.Disposables.CompositeDisposable.

+0

Tôi biết về sự kiện rò rỉ bộ nhớ .NET, nhưng tôi bỏ qua một thực tế rằng nó không quan trọng mà IObservable phân phối các nhà quan sát trên Finalize, bởi vì finalize không được gọi ở đây ... Cảm ơn! – TDaver

+1

Nếu tôi đã chỉ định cách 'IObservable ' nên hoạt động và nên được sử dụng, tôi sẽ chỉ định rằng mọi người tiêu dùng viết đúng phải giữ tham chiếu đến một địa chỉ 'IDisposable' được trả lại và triển khai nên tự xem xét (nếu không được khuyến khích) hủy bất kỳ đăng ký nào có liên quan 'IDisposable' đã bị loại khỏi phạm vi. – supercat

-1

Thực hành phổ biến là triển khai giao diện IDisposable và xử lý các thành viên dùng một lần của bạn tại đây.

+0

có nghĩa là làm cho VM của tôi triển khai IDisposable? ai sẽ gọi vứt bỏ điều đó?(hoặc tôi nên thực hiện một mô hình vứt bỏ với một finalizer?) – TDaver

+0

@TDaver Nó là khách hàng responsibily để gọi 'Vứt bỏ', do đó, nó phụ thuộc vào cách bạn nhanh chóng đối tượng của bạn. –

6

Bài hát không chính xác tại đây. Các ngữ nghĩa về cách Rx sử dụng IDisposable khác với .NET điển hình. IDisposable được trả lại từ Đăng ký là nếu bạn muốn hủy đăng ký trước đó so với kết thúc của IObservable. Nếu bạn không muốn làm điều này, làm phức tạp mã của bạn với tất cả các quản lý bổ sung dùng một lần là không cần thiết.

+0

Vì vậy, nếu nguồn sự kiện của tôi tăng OnCompleted, mọi thứ sẽ tự động hủy đăng ký? – TDaver

+0

TDaver: Có nó sẽ –

+0

Vâng nhưng "sự kiện" sẽ không hoàn thành bao giờ hết. Đó là để sử dụng Luồng quan sát và tương tự. Vì vậy, tôi cần ý tưởng của Gideon, trong khi bạn cũng chính xác ... – TDaver