问题
I have a large ReplaySubject that allows subscribers to receive the replay buffer and future notifications as normal. In addition, I would like to be able to take a "snapshot" of the current buffer and return that as a list synchronously, without having to subscribe.
Is there a way to do this?
thanks
回答1:
Can you not just subscribe, receive the items, then unsubscribe?
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;
}
That's assuming that subscribing to a ReplaySubject<T>
invokes the element handler synchronously, of course. You'd want to check that, but that's what I'd expect.
You should also consider whether you want to handle errors / completion somehow.
回答2:
ONLY because @PaulBetts said there's only one way to do it :)
note: I don't recommend this way; Use Skeet's method and you'll thank yourself later.
So the magic of a ReplaySubject<T>
all has to do with the fact it queues up any values it receives via OnNext
on an internal Queue<TimeInterval<T>>
. So we can write a wrapper that fiddles around inside the private details of the replay subject to get that info:
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();
}
}
Test rig:
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();
}
Result:
(TimeInterval<T>
is just value + time it came in)
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
来源:https://stackoverflow.com/questions/15185863/taking-a-snapshot-of-replaysubjectt-buffer