拍摄ReplaySubject <t>缓冲区</t>的快照

时间:2013-03-03 12:53:10

标签: .net system.reactive

我有一个大型ReplaySubject,允许订阅者正常接收重播缓冲区和未来通知。另外,我希望能够拍摄“快照” 当前缓冲区并将其作为列表同步返回,而不必订阅。

有办法做到这一点吗?

感谢

2 个答案:

答案 0 :(得分:1)

您是否可以订阅,收到商品,然后取消订阅?

public static List<T> Snapshot<T>(ReplaySubject<T> subject)
{
    List<T> snapshot = new List<T>();
    using (subject.Subscribe(item => snapshot.Add(item))
    {
        // Deliberately empty; subscribing will add everything to the list.
    }
    return snapshot;
}

当然,假设订阅ReplaySubject<T>同步调用元素处理程序。你想检查一下,但这就是我所期待的。

您还应该考虑是否要以某种方式处理错误/完成。

答案 1 :(得分:0)

因为@PaulBetts说只有一种方法可以做到这一点:)

注意:我不建议这样做;使用Skeet的方法,你以后会感谢自己。

因此ReplaySubject<T>所有内容的神奇之处在于它会在内部OnNext上通过Queue<TimeInterval<T>>对其收到的任何值进行排队。因此,我们可以编写一个包装器,在重放主题的私有细节内摆弄,以获取该信息:

public class FixedReplaySubject<T> : ISubject<T>
{
    private ReplaySubject<T> _inner;
    private Func<Queue<TimeInterval<T>>> _snapshotGetter;

    public FixedReplaySubject(ReplaySubject<T> source)
    {
        _inner = source;
        var expr = Expression.Lambda(
            typeof(Func<Queue<TimeInterval<T>>>), 
            Expression.Field(
                Expression.Constant(source), 
                source.GetType()
                    .GetField("_queue", BindingFlags.NonPublic|BindingFlags.Instance)));
        _snapshotGetter = (Func<Queue<TimeInterval<T>>>)expr.Compile();
    }

    public IEnumerable<TimeInterval<T>> Snapshot()
    {
        return _snapshotGetter();
    }

    public IDisposable Subscribe(IObserver<T> observer)
    {
        return _inner.Subscribe(observer);
    }
    public void OnNext(T value)
    {
        _inner.OnNext(value);
    }
    public void OnCompleted()
    {
        _inner.OnCompleted();
    }
    public void OnError(Exception error)
    {
        _inner.OnError(error);
    }
    public void Dispose()
    {
        _inner.Dispose();
    }
}

试验台:

void Main()
{
    var src = new ReplaySubject<int>();
    src.OnNext(1);
    src.OnNext(2);
    src.OnNext(3);
    src.OnNext(4);
    src.OnNext(5);
    src.OnNext(6);
    var heh = new FixedReplaySubject<int>(src);
    heh.Snapshot().Dump();
}

结果: (TimeInterval<T>只是值+时间)

1 00:00:00.0010265 
2 00:00:00.0010278 
3 00:00:00.0010278 
4 00:00:00.0010282 
5 00:00:00.0010282 
6 00:00:00.0010286