我有一个Observable,我想对它们进行模10分组。我想使结果成为热门的Observable,并且当一个新订户订阅时,他获得了所有GroupedObservable的播放,但没有获得Key,我想要最新的价值。我也要更新,跳过最新值。
在此示例中,为了简化起见,我们仅将模结果等于5进行工作。但是我希望我的解决方案适用于所有情况。
示例:
让我们在上一个示例中添加一些我们将订阅的时间点:
预期结果是:
S1接收最新消息:15,更新消息:以25开头的可观察值,并且更新%10 == 5,稍后将到达。 说明:S1将在15到达后得到通知,15是最新的元素,因此我希望它立即生效。第二个参数将是一个可观察到的参数,它将在以后生成25个元素,并在以后生成%10 == 5个元素。
S2接收最新消息:15,更新消息:以25开头的可观察值,并且更新%10 == 5,稍后将到达。 说明:S2将在订阅时收到通知,15是最新元素,所以我希望它立即生效。第二个参数将是一个可观察到的参数,它将在以后生成25个元素,并在以后生成%10 == 5个元素。
S3接收最新消息:25,更新:可观察到的更新%10 == 5,稍后将到达。 说明:S3将在订阅时收到通知,25是最新元素,所以我希望它立即生效。第二个参数是一个可观察的参数,将来会产生%10 == 5个元素。
以下是一些解决方法的尝试:
下面的代码使用Tuple和NUnit。
[Test]
public void WhenWeGroupByReplaying1()
{
var subject = new Subject<uint>();
var observable = subject.GroupBy(t => t%10)
.Select(t =>
{
var connectableObservable = t.Replay(1);
connectableObservable.Connect();
return (key: t.Key, updates: connectableObservable);
}).Replay();
observable.Connect();
// I will block on the First of the lambda below
var getLastAndUpdates = observable
.Select(t => (first: t.updates.First(),updates: t.updates.Skip(1)));
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[1] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[1] - UPDATE: {t2}"));
});
subject.OnNext(15);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[2] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[2] - UPDATE: {t2}"));
});
subject.OnNext(25);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[3] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[3] - UPDATE: {t2}"));
});
}
此解决方案将被阻止,如注释所示。
[Test]
public void WhenWeGroupByReplaying2()
{
var subject = new Subject<uint>();
var observable = subject.GroupBy(t => t, t => t, new ModuloEqualityComparer())
.Select(t =>
{
var connectableObservable = t.Publish(t.Key);
connectableObservable.Connect();
return (key: t.Key, updates: connectableObservable);
}).Replay();
observable.Connect();
var getLastAndUpdates = observable
.Select(t => (first: t.updates.First(),updates: t.updates.Skip(1)));
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[1] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[1] - UPDATE: {t2}"));
});
subject.OnNext(15);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[2] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[2] - UPDATE: {t2}"));
});
subject.OnNext(25);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[3] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[3] - UPDATE: {t2}"));
});
}
private class ModuloEqualityComparer : IEqualityComparer<uint>
{
public bool Equals(uint x, uint y)
{
return x % 10 == y % 10;
}
public int GetHashCode(uint obj)
{
return (obj % 10).GetHashCode();
}
}
结果:
[1] - FIRST: 15
[1] - UPDATE: 15
[2] - FIRST: 15
[1] - UPDATE: 25
[2] - UPDATE: 25
[3] - FIRST: 25
预期结果:(确切顺序不正确)
[1] - FIRST: 15
[2] - FIRST: 15
[1] - UPDATE: 25
[2] - UPDATE: 25
[3] - FIRST: 25
[Test]
public void WhenWeGroupByReplaying3()
{
var subject = new Subject<uint>();
var observable = subject.GroupBy(t => (key: t%10, value:t), t => t, new ModuloEqualityComparer2())
.Select(t =>
{
var connectableObservable = t.Publish(t.Key.Item2);
connectableObservable.Connect();
return (key: t.Key, updates: connectableObservable);
}).Replay();
observable.Connect();
var getLastAndUpdates = observable
.Select(t => (first: t.updates.First(),updates: t.updates.Skip(1)));
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[1] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[1] - UPDATE: {t2}"));
});
subject.OnNext(15);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[2] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[2] - UPDATE: {t2}"));
});
subject.OnNext(25);
getLastAndUpdates.Subscribe(t =>
{
Console.WriteLine($"[3] - FIRST: {t.first}");
t.updates.Subscribe(t2 => Console.WriteLine($"[3] - UPDATE: {t2}"));
});
}
private class ModuloEqualityComparer2 : IEqualityComparer<(uint,uint)>
{
private readonly ModuloEqualityComparer _moduloEqualityComparer = new ModuloEqualityComparer();
public bool Equals((uint, uint) x, (uint, uint) y)
{
return _moduloEqualityComparer.Equals(x.Item1, y.Item1);
}
public int GetHashCode((uint, uint) obj)
{
return _moduloEqualityComparer.GetHashCode(obj.Item1);
}
}
结果:
[1] - FIRST: 15
[1] - UPDATE: 15
[2] - FIRST: 15
[1] - UPDATE: 25
[2] - UPDATE: 25
[3] - FIRST: 25
预期结果:(确切顺序不正确)
[1] - FIRST: 15
[2] - FIRST: 15
[1] - UPDATE: 25
[2] - UPDATE: 25
[3] - FIRST: 25
感谢阅读。
答案 0 :(得分:0)
我不确定您要达到的目标,但是希望这对您有帮助:
您的代码有几处错误:
.First()
已过时是有原因的。您不应该在Rx中使用阻塞代码.Replay()
需要一个虚拟订阅才能正常工作。我不确定这是否是困扰您代码的原因,但是为了实现您的目标,您想要这样做。.Merge()
。 如果这不能解决您的问题,建议修改您的问题以描述您要使用Rx完成的工作。闻起来有点像XY situation。
代码如下:
var subject = new Subject<uint>();
var observable = subject.GroupBy(t => t % 10)
.Select(t => t.Replay(1).RefCount()).Replay().RefCount();
// dummy subscriptions required for Replay to work correctly.
var dummySub = observable.Merge().Subscribe();
observable
.Select(o => o.Select((t, index) => (t.Key, t.num, index)))
.Merge()
.Subscribe(t =>
{
if (t.index == 0)
Console.WriteLine($"[1] - FIRST: {t.num}");
else
Console.WriteLine($"[1] - UPDATE: {t.num}");
});
subject.OnNext(15);
observable
.Select(o => o.Select((t, index) => (t.Key, t.num, index)))
.Merge()
.Subscribe(t =>
{
if (t.index == 0)
Console.WriteLine($"[1] - FIRST: {t.num}");
else
Console.WriteLine($"[1] - UPDATE: {t.num}");
});
subject.OnNext(25);
observable
.Select(o => o.Select((t, index) => (t.Key, t.num, index)))
.Merge()
.Subscribe(t =>
{
if (t.index == 0)
Console.WriteLine($"[1] - FIRST: {t.num}");
else
Console.WriteLine($"[1] - UPDATE: {t.num}");
});