For compatibility reasons I am writing a custom serializer for a generic protobuf message.
I a using Google.Protobuf 3.11.3 from NuGet and used protoc to generate my C# classes.
Given the proto file
message Foo {
optional string other = 1;
optional Bar bar = 2;
}
message Bar {
optional string hello = 1;
}
I have a serialize method
public static string Serialize(IMessage message)
{
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
var result = WriteFields(message, message.Descriptor.Fields, 0);
return result.ToString();
}
and WriteFields
private static StringBuilder WriteFields(IMessage message, MessageDescriptor.FieldCollection fields, int depth)
{
var sb = new StringBuilder();
foreach (var field in fields.InFieldNumberOrder())
{
if (field.Accessor.HasValue(message))
{
if (field.FieldType == FieldType.Message)
{
sb.Append($"{field.Name} {{\n");
sb.Append(WriteFields(message, field.MessageType.Fields, depth + 1));
sb.Append("}\n");
}
else
{
sb.Append($"{field.Name}: {field.Accessor.GetValue(message)}\n");
}
}
}
return sb;
}
The first pass of the foreach-loop runs fine. Foo.other is written as expected.
The second pass fails, at this point I know the field has FieldType.Message and I call WriteFields recursively to write the fields from Bar.
I get an InvalidCastException at field.Accessor.HasValue(message)now.
System.InvalidCastException : Unable to cast object of type 'Test.Foo' to type 'Test.Bar'.
at Google.Protobuf.Reflection.ReflectionUtil.ReflectionHelper`2.<>c__DisplayClass4_0.<CreateFuncIMessageBool>b__0(IMessage message) in T:\src\github\protobuf\csharp\src\Google.Protobuf\Reflection\ReflectionUtil.cs:line 204
at Test.Parser.WriteFields(IMessage message, FieldCollection fields, Int32 depth) in C:\src\Project\Parser.cs:line 85
I need to either
A) Convert the FieldDescriptor Bar to IMessage Bar
or
B) Find some other way to get the value than passing IMessage down the chain
I am not able to find out how to to this.