“源数据中的无效字段:0”使用时出现异常
" Invalid field in source data: 0 " exception when using
我正在序列化许多对象并将其写入流,然后使用 Protobuf.net 从流中反序列化这些对象。
对象类型是在运行时确定的,所以我不得不使用NonGeneric方法"TryDeserializeWithLengthPrefix"。
我一直收到 "Invalid field in source data: 0" 异常。但是当我使用通用方法 "DeserializeWithLengthPrefix()" 时它工作正常。
而且非常奇怪,一开始我得到“源数据中的无效字段:0”,但是当我更改数组长度时,我开始得到 "System.InvalidOperationException"!第一个异常仅在长度为 5 或 9 时发生。我尝试使用 class 而不是 int[],但结果是一样的。
下面是测试代码,
非常感谢您的帮助。
MemoryStream outputStream = new MemoryStream();
MemoryStream inputStream;
for (int i = 0; i < 10; i++)
{
//an int array as the object to serialize
var data = new int[] { 1, 2, 3, 4, 5 };
Serializer.SerializeWithLengthPrefix(outputStream, data, PrefixStyle.Base128);
}
var dataBytes = outputStream.ToArray();
inputStream = new MemoryStream(dataBytes);
while (inputStream.Position != inputStream.Length)
{
object output;
//not working, "System.InvalidOperationException" or "Invalid field in source data: 0" depend on the lenth of the array
Serializer.NonGeneric.TryDeserializeWithLengthPrefix(inputStream, PrefixStyle.Base128, t => typeof(int[]), out output);
//working! every time
var output = Serializer.DeserializeWithLengthPrefix<int[]>(inputStream, PrefixStyle.Base128);
foreach (var num in (int[])output)
{
Console.WriteLine(num);
}
}
由于可选参数,它们的场景略有不同。您正在使用的 SerializeWithLengthPrefix
和 DeserializeWithLengthPrefix
方法有一个可选参数 - 如果省略 - 默认为零。这意味着您使用零进行序列化,但 没有 字段号(零字段号在 protobuf 中永远不合法)。有些人需要那个。还有另一个重载允许您指定字段编号 以及 长度前缀。
您正在使用的 TryDeserializeWithLengthPrefix
的重载旨在用于第二种情况 - 具体来说,您与委托一起使用的版本旨在允许您告诉序列化程序它应该是什么类型考虑 基于字段编号 (在您的情况下,t => typeof(int[])
会 return 每个标签 t
相同的事情)。如果您打算使用该版本进行反序列化,则必须在序列化时包含一个字段编号,例如:
Serializer.SerializeWithLengthPrefix(
outputStream, data, PrefixStyle.Base128, 1);
和
var output = Serializer.DeserializeWithLengthPrefix<int[]>(
inputStream, PrefixStyle.Base128, 1);
这应该 也 与行一起正常工作:
Serializer.NonGeneric.TryDeserializeWithLengthPrefix(
inputStream, PrefixStyle.Base128, t => typeof(int[]), out output);
(你应该发现 t
是 1
)。
或者,如果您不想在数据中使用字段编号,您可以使用 TryReadLengthPrefix(...)
获取长度,然后创建一个 ProtoReader
来指定 长度.
附带说明:您通常应该避免在 Stream
中检查 .Length
与 .Position
,因为 .Length
通常不可用(并且 .Position
有时也不支持)。不过,在 MemoryStream
和 FileStream
之类的情况下,您会侥幸逃脱。最好只使用 while
而不是 Try...(...)
方法,returns false
如果它找到流的结尾。
我正在序列化许多对象并将其写入流,然后使用 Protobuf.net 从流中反序列化这些对象。
对象类型是在运行时确定的,所以我不得不使用NonGeneric方法"TryDeserializeWithLengthPrefix"。
我一直收到 "Invalid field in source data: 0" 异常。但是当我使用通用方法 "DeserializeWithLengthPrefix()" 时它工作正常。
而且非常奇怪,一开始我得到“源数据中的无效字段:0”,但是当我更改数组长度时,我开始得到 "System.InvalidOperationException"!第一个异常仅在长度为 5 或 9 时发生。我尝试使用 class 而不是 int[],但结果是一样的。
下面是测试代码, 非常感谢您的帮助。
MemoryStream outputStream = new MemoryStream();
MemoryStream inputStream;
for (int i = 0; i < 10; i++)
{
//an int array as the object to serialize
var data = new int[] { 1, 2, 3, 4, 5 };
Serializer.SerializeWithLengthPrefix(outputStream, data, PrefixStyle.Base128);
}
var dataBytes = outputStream.ToArray();
inputStream = new MemoryStream(dataBytes);
while (inputStream.Position != inputStream.Length)
{
object output;
//not working, "System.InvalidOperationException" or "Invalid field in source data: 0" depend on the lenth of the array
Serializer.NonGeneric.TryDeserializeWithLengthPrefix(inputStream, PrefixStyle.Base128, t => typeof(int[]), out output);
//working! every time
var output = Serializer.DeserializeWithLengthPrefix<int[]>(inputStream, PrefixStyle.Base128);
foreach (var num in (int[])output)
{
Console.WriteLine(num);
}
}
由于可选参数,它们的场景略有不同。您正在使用的 SerializeWithLengthPrefix
和 DeserializeWithLengthPrefix
方法有一个可选参数 - 如果省略 - 默认为零。这意味着您使用零进行序列化,但 没有 字段号(零字段号在 protobuf 中永远不合法)。有些人需要那个。还有另一个重载允许您指定字段编号 以及 长度前缀。
您正在使用的 TryDeserializeWithLengthPrefix
的重载旨在用于第二种情况 - 具体来说,您与委托一起使用的版本旨在允许您告诉序列化程序它应该是什么类型考虑 基于字段编号 (在您的情况下,t => typeof(int[])
会 return 每个标签 t
相同的事情)。如果您打算使用该版本进行反序列化,则必须在序列化时包含一个字段编号,例如:
Serializer.SerializeWithLengthPrefix(
outputStream, data, PrefixStyle.Base128, 1);
和
var output = Serializer.DeserializeWithLengthPrefix<int[]>(
inputStream, PrefixStyle.Base128, 1);
这应该 也 与行一起正常工作:
Serializer.NonGeneric.TryDeserializeWithLengthPrefix(
inputStream, PrefixStyle.Base128, t => typeof(int[]), out output);
(你应该发现 t
是 1
)。
或者,如果您不想在数据中使用字段编号,您可以使用 TryReadLengthPrefix(...)
获取长度,然后创建一个 ProtoReader
来指定 长度.
附带说明:您通常应该避免在 Stream
中检查 .Length
与 .Position
,因为 .Length
通常不可用(并且 .Position
有时也不支持)。不过,在 MemoryStream
和 FileStream
之类的情况下,您会侥幸逃脱。最好只使用 while
而不是 Try...(...)
方法,returns false
如果它找到流的结尾。