所以我试图使用被动反应来重新组合由ID标识的分块消息,并且在终止最终的observable时出现问题。我有一个Message类,包括Id,Total Size,Payload,Chunk Number和Type,并有以下客户端代码:
我需要计算在运行时获取的消息数
(from messages in
(from messageArgs in Receive select Serializer.Deserialize<Message>(new MemoryStream(Encoding.UTF8.GetBytes(messageArgs.Message))))
group messages by messages.Id into grouped select grouped)
.Subscribe(g =>
{
var cache = new List<Message>();
g.TakeWhile((int) Math.Ceiling(MaxPayload/g.First().Size) < cache.Count)
.Subscribe(cache.Add,
_ => { /* Rebuild Message Parts From Cache */ });
});
首先,我按照其唯一ID创建一个分组的可观察过滤消息,然后我尝试缓存每个组中的所有消息,直到我将它们全部收集起来,然后我对它们进行排序并将它们放在一起。以上似乎阻止了g.First()。
我需要一种方法来计算从第一个(或任何)消息中获取的数量,但是很难这样做。有什么帮助吗?
答案 0 :(得分:3)
First
是一个阻止运算符(如何返回T
而不是IObservable<T>
?)
我认为使用Scan
(随着时间的推移构建聚合)可能就是您所需要的。使用Scan
,您可以在“构建器”对象中隐藏消息重构的“状态”。
MessageBuilder.IsComplete
(或您的要求是什么)时, MaxPayload
返回true。 MessageBuilder.Build()
然后返回重建的消息。
我还将您的“邮件构建”代码移动到SelectMany
,这会将构建的邮件保留在monad中。
(将代码重新格式化为扩展方法的道歉,我发现很难读/写混合LINQ语法)
Receive
.Select(messageArgs => Serializer.Deserialize<Message>(
new MemoryStream(Encoding.UTF8.GetBytes(messageArgs.Message))))
.GroupBy(message => message.Id)
.SelectMany(group =>
{
// Use the builder to "add" message parts to
return group.Scan(new MessageBuilder(), (builder, messagePart) =>
{
builder.AddPart(messagePart);
return builder;
})
.SkipWhile(builder => !builder.IsComplete)
.Select(builder => builder.Build());
})
.Subscribe(OnMessageReceived);