.Net Core 3 预览版 SequenceReader 长度定界解析
.Net Core 3 Preview SequenceReader Length Delimited Parsing
我正在尝试使用 SequenceReader<T>
in .Net Core Preview 8 to parse Guacamole Protocol 网络流量。
流量可能如下所示:
5.error,14.some text here,1.0;
这是单曲error instruction。有 3 个字段:
- OpCode =
error
- 原因=
some text here
- 状态 =
0
(参见 Status Codes)
字段以逗号分隔(以分号结尾),但每个字段也有长度前缀。我想这样你就可以解析如下内容:
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;
}
根据我对 initial proposal 的理解,这应该可行,但我认为也可以简化,因为提案中的一些方法比 .Net Core 中提供的方法更容易一些预览 8.
但是,此代码的问题在于 SequenceReader
似乎并不像我预期的那样 Advance
。它的 Position
and Consumed
属性在前进时保持不变,所以我在最后切片的 element
是 始终 一个空序列。
我需要做什么才能正确解析此协议?
我猜.Reader
这里是一个属性;这很重要,因为 SequenceReader<T>
是一个 可变结构 ,但每次访问 .SomeProperty
时,您都在使用一个 独立副本 的 reader。可以将其隐藏在 属性 后面,但您需要确保 使用本地 ,然后 完成后推回 ,即
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
) 中,您 还没有更改状态,因为您只改变了本地独立克隆。
你可以也考虑 ref
-return 属性 .Reader
.
我正在尝试使用 SequenceReader<T>
in .Net Core Preview 8 to parse Guacamole Protocol 网络流量。
流量可能如下所示:
5.error,14.some text here,1.0;
这是单曲error instruction。有 3 个字段:
- OpCode =
error
- 原因=
some text here
- 状态 =
0
(参见 Status Codes)
字段以逗号分隔(以分号结尾),但每个字段也有长度前缀。我想这样你就可以解析如下内容:
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;
}
根据我对 initial proposal 的理解,这应该可行,但我认为也可以简化,因为提案中的一些方法比 .Net Core 中提供的方法更容易一些预览 8.
但是,此代码的问题在于 SequenceReader
似乎并不像我预期的那样 Advance
。它的 Position
and Consumed
属性在前进时保持不变,所以我在最后切片的 element
是 始终 一个空序列。
我需要做什么才能正确解析此协议?
我猜.Reader
这里是一个属性;这很重要,因为 SequenceReader<T>
是一个 可变结构 ,但每次访问 .SomeProperty
时,您都在使用一个 独立副本 的 reader。可以将其隐藏在 属性 后面,但您需要确保 使用本地 ,然后 完成后推回 ,即
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
) 中,您 还没有更改状态,因为您只改变了本地独立克隆。
你可以也考虑 ref
-return 属性 .Reader
.