C# 使用FieldDescriptor迭代未知的重复protobuf字段
我试图编写一个通用的方法来迭代protobuf消息,基本上创建一个对象树 到目前为止我有C# 使用FieldDescriptor迭代未知的重复protobuf字段,c#,iterator,protocol-buffers,C#,Iterator,Protocol Buffers,我试图编写一个通用的方法来迭代protobuf消息,基本上创建一个对象树 到目前为止我有 IMessage message = new Message() as IMessage; foreach (FieldDescriptor field in message.Descriptor.Fields.InFieldNumberOrder()) { if (field.FieldType == Google.Protobuf.Reflecti
IMessage message = new Message() as IMessage;
foreach (FieldDescriptor field in message.Descriptor.Fields.InFieldNumberOrder())
{
if (field.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
if (field.IsRepeated)
{
// How to do this?
}
else
{
Children.Add(new MessageNode(field, (IMessage)field.Accessor.GetValue(message)));
}
}
else
{
Children.Add(new FieldNode(field, message));
}
}
除了重复的字段外,工作正常(地图字段可能会出现同样的问题)
如果对重复字段执行field.Accessor.GetValue(message)
,则会得到一个对象[RepeatedField]
,其中T
是一些嵌套消息。但是,我无法迭代类型为object
的内容。
我尝试将对象强制转换为RepeatedField
,但这只返回0
是否有任何方法可以在不知道内部类型的情况下迭代重复的字段?我只需要一个指向内部对象的
IMessage
指针,从那里我可以使用IMessage
中的描述符,我不知道在过去两天里我有多瞎试图解决这个问题
在Accessor
的GetValue
文档中,它说
对于重复的值,这将是IList实现。对于映射值,这将是一个IDictionary实现
是的,IList d=field.Accessor.GetValue(message)作为IList
执行此操作并提供重复字段的可编辑集合。如中所述,根据字段。Accessor.GetValue(protobufMessage)
将为重复字段返回一个IList
,为映射字段返回一个IDictionary
下面是我编写的一些代码,它使用字段描述符递归地遍历protobuf消息。它可能是执行其他操作而不是打印的有用起点
public static void PrintProtobufMessage(IMessage protobufMessage)
{
if (protobufMessage == null)
{
return;
}
foreach (var field in protobufMessage.Descriptor.Fields.InFieldNumberOrder())
{
if (field.IsMap)
{
// for map fields, the field type is always a MapField, inside of which are contained a keyField and valueField
//var keyField = field.MessageType.Fields.InFieldNumberOrder()[0];
var valueField = field.MessageType.Fields.InFieldNumberOrder()[1];
IDictionary mapFields = field.Accessor.GetValue(protobufMessage) as IDictionary;
if (mapFields != null)
{
foreach (DictionaryEntry mapField in mapFields)
{
Console.WriteLine("Iterating Map, Field {0} ({1}): Key {2}:", field.FieldNumber, field.Name, mapField.Key);
if (valueField.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
PrintProtobufMessage(mapField.Value as IMessage);
}
else
{
PrintProtobufField(valueField, mapField.Value);
}
}
}
}
else if (field.IsRepeated)
{
IList repeatedFieldValues = field.Accessor.GetValue(protobufMessage) as IList;
if (repeatedFieldValues != null)
{
foreach (var repeatedFieldValue in repeatedFieldValues)
{
// for repeated fields, the field type represents each element in the list, handle them accordingly
if (field.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
PrintProtobufMessage(repeatedFieldValue as IMessage);
}
else
{
PrintProtobufField(field, repeatedFieldValue);
}
}
}
}
else
{
if (field.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
var fieldValue = field.Accessor.GetValue(protobufMessage);
PrintProtobufMessage(fieldValue as IMessage);
}
else
{
PrintProtobufField(field, protobufMessage);
}
}
}
}
public static void PrintProtobufField(FieldDescriptor field, IMessage protobufMessage)
{
var fieldValue = field.Accessor.GetValue(protobufMessage);
PrintProtobufField(field, fieldValue);
}
public static void PrintProtobufField(FieldDescriptor field, object fieldValue)
{
if (fieldValue != null)
{
Console.WriteLine(
"Field {0} ({1}): {2}",
field.FieldNumber,
field.Name,
fieldValue
);
}
}