簡體   English   中英

如何在不自行維護狀態的情況下獲取可觀察流中的項目計數?

[英]How to get the count of items in an observable stream without maintaining state yourself?

如何使用Rx習語在任何給定的時間點獲得這所學校的學生人數,而不必自己保持School班級的狀態?

using System;
using System.Reactive.Subjects;

namespace SchoolManagementSystem
{
    public class School
    {
        private ISubject<Student> _subject = null;
        private int _maxNumberOfSeats;
        private int _numberOfStudentsAdmitted;

        public string Name { get; set; }

        public School(string name, int maxNumberOfSeats)
        {
            Name = name;

            _maxNumberOfSeats = maxNumberOfSeats;

            _numberOfStudentsAdmitted = 0;

            _subject = new ReplaySubject<Student>();
        }

        public void AdmitStudent(Student student)
        {
            try
            {
                if (student == null)
                    throw new ArgumentNullException("student");

                if (_numberOfStudentsAdmitted == _maxNumberOfSeats)
                {
                    _subject.OnCompleted();
                }

                // Obviously can't do this because this will
                // create a kind of dead lock in that it will
                // wait for the _subject to complete, but I am 
                // using the same _subject to issue notifications.

                // _numberOfStudentsAdmitted = _subject.Count().Wait();


                // OR to keep track of state myself
                Interlocked.Increment(ref _numberOfStudentsAdmitted);

                _subject?.OnNext(student);
            }
            catch(Exception ex)
            {
                _subject.OnError(ex);
            }
        }

        public IObservable<Student> Students
        {
            get
            {
                return _subject;
            }
        }
    }
}

還是這與使用Rx設計的組件原理不協調?

這是客戶端應該負責的事情(獲取計數並在onNext處理程序中產生所有副作用)嗎? 並且可觀察對象應該僅充當無狀態信號源或門,就像硬件中斷例程那樣,簡單地向CPU發出感興趣的信號嗎?

在那種情況下,我們失去了可觀察到的信號完成標准。 那么應該如何知道何時完成?

您可以在_subject序列上使用Count()方法。 它將自己創建一個可觀察的序列,其中產生的每個值代表_subject最新的學生_subject

然后,您可以對這個學生計數值序列進行反應。 Zip()操作在這方面可能很有用,因為它的優點是當其內部序列中的任何一個完成時,可以完成結果序列,您可以使用TakeWhile強制執行該操作

結果看起來像這樣

Observable.Zip(
    _subject.Select(student => != null ? student ? throw new ArgumentNullException("student")), 
    _subject.Count().TakeWhile(studentCount => studentCount < _maxNumberOfSeats),
    (student, count) => student 
);

AdmitStudent方法主體中剩下要做的就是簡單地用_subject?.OnNext(student)將任何新學生推入序列(就像您已經做過的那樣),但是沒有額外的邏輯。 您還可以對此進行一些修改,以確保_subject本身也能在達到最大學生人數后完成,但是我不確定您的業務規則,因此我_subject您自己決定。

我可以建議的最后一件事是,如果要使用Rx類型的擴展名,並看看這個網站的使用情況,該網站會大量使用它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM