4

我正在尝试SequenceReader<T>在 .Net Core Preview 8 中使用来解析鳄梨酱协议网络流量。

流量可能如下所示:

5.error,14.some text here,1.0;

这是一个单一的错误指令。有3个字段:

  • 操作码 =error
  • 原因 =some text here
  • 状态 = 0(见状态代码

这些字段以逗号分隔(以分号结尾),但它们也具有每个字段的前缀长度。我想这样你就可以解析类似的东西:

5.error,24.some, text, with, commas,1.0;

产生Reason= some, text, with, commas

简单的逗号分隔解析很简单(有或没有SequenceReader)。但是,为了利用长度,我尝试了以下方法:

public static bool TryGetNextElement(this ref SerializationContext context, out ReadOnlySequence<byte> element)
{
    element = default;
    var start = context.Reader.Position;
    if (!context.Reader.TryReadTo(out ReadOnlySequence<byte> lengthSlice, Utf8Bytes.Period, advancePastDelimiter: true))
        return false;
    if (!lengthSlice.TryGetInt(out var length))
        return false;
    context.Reader.Advance(length);
    element = context.Reader.Sequence.Slice(start, context.Reader.Position);
    return true;
}

根据我对最初提案的理解,这应该可行,但我认为也可以简化,因为提案中的某些方法比 .Net Core Preview 8 中提供的方法更容易一些。

但是,此代码的问题在于SequenceReader它似乎Advance不像我所期望的那样。它的PositionConsumed属性在前进时保持不变,所以最后的elementI 切片始终是一个空序列。

为了正确解析此协议,我需要做什么?

4

1 回答 1

3

我猜这.Reader是一个属性;这很重要,因为SequenceReader<T>它是一个可变结构,但每次访问时,.SomeProperty您都在使用阅读器的隔离副本。将其隐藏在属性后面很好,但您需要确保您与本地人一起工作,然后在完成时推回,即

var reader = context.Reader;
var start = reader.Position;
if (!reader.TryReadTo(out ReadOnlySequence<byte> lengthSlice,
        Utf8Bytes.Period, advancePastDelimiter: true))
    return false;
if (!lengthSlice.TryGetInt(out var length))
    return false;
reader.Advance(length);
element = reader.Sequence.Slice(start, reader.Position);

context.Reader = reader; // update position
return true;

请注意,这样做的一个很好的特性是,在失败的情况下return false),您还没有更改状态,因为您只是在改变本地独立克隆。


您还可以考虑为 .return 设置一个ref-return 属性.Reader

于 2019-08-29T11:29:26.083 回答