"源数据中的字段无效:0"使用时的异常

时间:2015-12-25 10:16:18

标签: c# protocol-buffers protobuf-net

我正在序列化许多对象并将其写入流,然后使用Protobuf.net从流中反序列化这些对象。

对象类型是在运行时确定的,所以我必须使用NonGeneric方法" TryDeserializeWithLengthPrefix"。

我不断收到源数据中的"无效字段:0"例外。但是当我使用泛型方法" DeserializeWithLengthPrefix()"它工作正常。

非常奇怪的是,我得到了#34;源数据中的字段无效:0"起初,但是当我更改数组lenth时,我开始得到" System.InvalidOperationException"!第一个例外仅在lenth为5或9时发生。我尝试使用类而不是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);
            }
        }

1 个答案:

答案 0 :(得分:0)

由于可选参数,它们的情况略有不同。您使用的SerializeWithLengthPrefixDeserializeWithLengthPrefix方法有一个可选参数 - 如果省略 - 默认为零。这意味着您使用零序列化,但没有字段编号(零字段编号在protobuf中从不合法)。有些人需要这样做。还有另一个重载允许您指定字段编号以及长度前缀。

您正在使用的TryDeserializeWithLengthPrefix的重载旨在用于第二种情况 - 具体而言,您与委托一起使用的版本旨在让您告诉序列化程序它应该考虑哪种类型基于字段编号(在您的情况下,t => typeof(int[])会为每个标记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);

(你会发现t1)。

或者,如果您不想在数据中使用字段编号,则可以使用TryReadLengthPrefix(...)获取长度,然后创建ProtoReader以指定确切的长度

作为旁注:您通常应该避免在.Length中检查.PositionStream,因为.Length通常不可用(.Position是有时也不支持)。不过,您可以在MemoryStreamFileStream之类的内容中使用它。最好只使用while而不是Try...(...)方法,如果它找到了流的末尾,则返回false