繁体   English   中英

如何从C#中的主题获取观察者列表

[英]How do I get list of observers from a Subject in C#

我有一个主题(System.Reactive.Subjects),我订阅了多个观察者。 是否可以从该主题中获得观察员名单?

基本上,我需要将观察者从主题A复制到主题B。

var newSubject = new Subject();
if (oldSubject.HasObservers)
{
    var observers = oldSubject. <-- not quite sure what to do here.
    foreach(var obs in observers)
    {
        newSubject.Subscribe(obs);
    }
}

Update1-为什么我需要这样做

我无法控制onCompleted到oldSubject的另一个库。 然后,他们将再次打电话询问该主题。 如果返回oldSubject,则所有订阅更新的观察者将不再获得更新。 因此,我正在考虑创建一个新的主题,将活跃的观察者坚持下去,然后返回这个新主题。

Update2-示例代码问题的完整上下文

我正在使用一个公开Observable的库。 但是,此可观察对象仅接受一个观察者(请不要问我为什么和如何,这是我无法在公共论坛上讨论的信息)。 因此,我正在编写一层Observable(使用Subject),该层将允许多个观察者订阅更新。

我传递给另一个库的单个观察者如下:

public class DataObserver<T> : IObserver<IList<ChangeEvent<T>>>
{
    public DataObserver(string id, Subject<Tuple<string, IList<ChangeEvent<T>>>> subject)
    {
        Id = id;
        Subject = subject;
    }

    public Subject<Tuple<string, IList<ChangeEvent<T>>>> Subject { get; set; }

    public string Id { get; }

    public void OnCompleted()
    {
        Subject?.OnCompleted();
    }

    public void OnError(Exception error)
    {
        Subject?.OnError(error);
    }

    public void OnNext(IList<ChangeEvent<T>> value)
    {
        Subject?.OnNext(new Tuple<string, IList<ChangeEvent<T>>>(Id, value));
    }
}

现在,另一个库通过下面的MySingletonClass中的TryGetObserver方法获取此观察者:

public MySingletonClass 
{
    public MySingletonClass() 
    {
        DataObservables = new ConcurrentDictionary<string, Tuple<Type, dynamic>>();
    }   

    public ConcurrentDictionary<string, Tuple<Type, dynamic>> DataObservables { get; set; }

    public (bool Success, IObserver<IList<ChangeEvent<T>>> Observer) TryGetObserver<T>(string id)
    {
        var dataSubject = new Subject<Tuple<string, IList<ChangeEvent<T>>>>();
        var dataObserver = new DataObserver<T>(id, dataSubject);
        var hasObserver = DataObservables.ContainsKey(id);
        if (hasObserver)
        {
            var val = DataObservables[id];
            if (val.Item2 is DataObserver<T> extantObserver && extantObserver.Subject.HasObservers)
            {
                // var observers = extantObserver.Subject. <-- This is not going to work.
                // foreach(var obs in observers)
                // {
                //    dataObserver.Subject.Subscribe(obs);
                // }
            }
        }

        DataObservables.TryAdd(id, new Tuple<Type, dynamic>(typeof(T), dataObserver));

        return (true, dataObserver);
    }
}

因此,另一个库将在第一次调用TryGetObserver,而我将返回正确的对象。 然后,它将在某个时刻从该对象的Subject中调用onCompleted。 随后,它将再次调用TryGetObserver,现在我必须返回一个包含所有先前订阅的观察者的新Subject。

我通过以下方法解决了这个问题:

  • 创建一个自定义主题,将其围绕本机主题。
  • 调用OnCompleted时不调用subject.OnCompleted(请参阅上面的问题描述)。 相反,当流被标记为已完成时,我使用了自己的自定义跟踪器来完成此工作。 这确保了不会向订阅的观察者发出信号,告知该流已停止,并且我可以重用它们。 事实证明,由于框架将私有成员isStopped(在每个观察者上)标记为1,因此只要在可观察对象上调用OnCompleted,复制观察者的原始想法就永远不会奏效。

这不是理想的,但是对于我们的软件而言,这是可以接受的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM