使用Reactives合并分块消息

时间:2011-02-11 17:14:38

标签: linq c#-4.0 system.reactive

所以我试图使用被动反应来重新组合由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()。

我需要一种方法来计算从第一个(或任何)消息中获取的数量,但是很难这样做。有什么帮助吗?

1 个答案:

答案 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);