bugfix> c# > 投稿

Observablesについて質問があります(私が投稿した この本の出版社のサブフォーラムに掲載されていますが、まだ回答を待っています)。

オブザーバブルを手作りするのではなく、標準的な方法として提供されているヘルパーメソッドを使用します。しかし、学問的な興味から、観察可能なものを手作りするために必要なことを知りました。

サブスクライブメソッドの最後にDisposable.Emptyが返された本で実装を確認しました。 コードは以下のようなものです。

public class MyObservable : IObservable<int>
{
    public IDisposable Subscribe(IObserver<int> observer)
    {
        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(1000);
            observer.OnNext(i);
        }
        observer.OnCompleted();
        return Disposable.Empty;
    }
}

Disposeが呼び出されたときに実際に登録解除につながる適切なDisposableを返したい場合はどうすればよいですか?

私はこれを使用してそれにひびがありました観測可能 これは観察者

サブスクリプションハンドラーを導入する必要がありました

public class SubscriptionHandler : IDisposable
{
    private readonly List<IObserver<int>> _listOfObservers;
    private readonly IObserver<int> _currentObserver;
    public SubscriptionHandler(List<IObserver<int>> currentListOfObservers, IObserver<int> currentObserver)
    {
        _listOfObservers = currentListOfObservers;
        _currentObserver = currentObserver;
    }
    public void Dispose()
    {
        if (_currentObserver != null && _listOfObservers.Contains(_currentObserver))
        {
            _listOfObservers.Remove(_currentObserver);
        }
    }
}

これはObservableのコードです

public class MyObservable : IObservable<int>
{
    private List<IObserver<int>> _listOfSubscribedObservers = new List<IObserver<int>>();
    public IDisposable Subscribe(IObserver<int> observer)
    {
        if (!_listOfSubscribedObservers.Contains(observer))
        {
            _listOfSubscribedObservers.Add(observer);
        }
        Task.Run(() =>
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                observer.OnNext(i);
            }
            observer.OnCompleted();
        });
        return new SubscriptionHandler(_listOfSubscribedObservers, observer);
    }
}

私は何かが欠けていると感じています。手作りのObservableに有意義なDisposableを返すように構築する必要がありますか、これはObservable createヘルパーメソッドにのみ付属していますか?

PS:投票する場合は、質問をする際に間違いを繰り返しないように、コメントに理由を記入してください。

回答 1 件
  • これはすべて、Rxデザインの内部のデモンストレーションであることを明確にする必要があります。あなたはクラス AnonymousObservable<T> を見ることができます 、   AnonymousObserver<T> 、および AnonymousDisposable 、これはフレームワークがそれを行う方法です。かなり簡単です。ただし、このコードはほとんど使用しないでください。むしろ、 Disposable.Create などを使用してください。  および Observable.CreateIObservable を実装している場合 、あなたはほぼ間違いなく間違っています。

    基本的な考え方は次のとおりです。オブザーバブルは IDisposable を生成する必要があります  これにより、オブザーバブルの内部オブザーバーリストから関連オブザーバーが削除されます。あなたのコードは(間違って)削除していますすべて 内部リストからのオブザーバー。

    機能的に簡単に作成できる基本的な使い捨て品は次のとおりです。このコードでは、 GenericDisposable.Create   Disposable.Create(Action a) と同じです 。

    public class GenericDisposable : IDisposable
    {
        public static IDisposable Create(Action disposeAction)
        {
            return new GenericDisposable(disposeAction);
        }
        private readonly Action _disposeAction;
        public GenericDisposable(Action disposeAction)
        {
            _disposeAction = disposeAction;
        }
        public void Dispose()
        {
            _disposeAction();
        }
    }
    
    

    ...そして、これは観察可能な実装例です:

    public class SendIntMessages : IObservable<int>
    {
        private readonly HashSet<IObserver<int>> _observers = new HashSet<IObserver<int>>();
        protected void OnNext(int i)
        {
            foreach (var o in _observers)
                o.OnNext(i);
        }
        protected void OnError(Exception e)
        {
            foreach (var o in _observers)
                o.OnError(e);
        }
        protected void OnCompleted()
        {
            foreach (var o in _observers)
                o.OnCompleted();
        }
        public void SendIntMessage(int i)
        {
            OnNext(i);
        }
        public void EndStream()
        {
            OnCompleted();
        }
        public void SendError(Exception e)
        {
            OnError(e);
        }
        public IDisposable Subscribe(IObserver<int> observer)
        {
            _observers.Add(observer);
            return GenericDisposable.Create(() => _observers.Remove(observer));
        }
    }
    
    

    これは、長時間実行される、ホットな観測可能です。オブザーバーを追跡し、ディスポーザブルはそれらをサブスクライブ解除します。

    対照的に、この観察可能なものを考慮してください:

    public class CountTo5 : IObservable<int>
    {
        public IDisposable Subscribe(IObserver<int> observer)
        {
            observer.OnNext(1);
            observer.OnNext(2);
            observer.OnNext(3);
            observer.OnNext(4);
            observer.OnNext(5);
            return GenericDisposable.Create(() => {});
        }
    }
    
    

    これは、すぐに実行される「コールド」オブザーバブルです。途中で退会する方法はありません。使い捨てを入手するまでに、オブザーバブルは終了しました。

    Disposable.Empty   DisposableCreate(() => {}) の簡単なショートハンド 。

あなたの答え