如何从消息类型的 DescriptorProto 中获取 Parser?

How to get a Parser from a DescriptorProto of a message type?

在第一个#region 中创建后,以下代码使用 Google.Protobuf library

在第二个#region 中将消息的有线格式二进制文件转换为 json 字符串
static void Main(string[] args)
{
    #region create example object and write it to a file in binary wire format

    var john = new Person // defined in Addressbook.cs protoc-compiled from addressbook.proto
    {
        Id = 1234,
        Name = "John Doe",
        Email = "jdoe@example.com",
        Phones = { new PhoneNumber { Number = "555-4321", Type = PhoneType.Home } }
    };

    var binaryFileName = "john";
    using (var output = File.Create(binaryFileName))
    {
        john.WriteTo(output);
    }

    #endregion

    #region convert wire format binary to json

    using (var input = File.OpenRead(binaryFileName))
    {
        var message = Person.Descriptor.Parser.ParseFrom(input);
        var json = new JsonFormatter(JsonFormatter.Settings.Default).Format(message);

        Console.WriteLine(json);
    }

    #endregion
}

我想使用 protobuf-net 库通过反射从 .proto 文件而不是从该 .proto 文件编译的源代码获取 Descriptor 来重新创建此功能。

我得到了消息的描述符。 我怎样才能从 DescriptorProto 得到一个 MessageParser 的等价物?

static void Main(string[] args)
{
    var binaryFileName = "john";

    var set = new FileDescriptorSet();
    set.Add("addressbook.proto", true, new StreamReader("addressbook.proto"));
    set.Process();
    
    var errors = set.GetErrors();
    foreach (var error in errors)
    {
        Console.WriteLine(error);
    }
    
    foreach (var file in set.Files)
    {
        Console.WriteLine(file.Name);

        foreach (var messageType in file.MessageTypes)
        {
            Console.WriteLine(messageType.Name);
        }
    }
    
    var personType = set.Files.SelectMany(file => file.MessageTypes).FirstOrDefault(messageType => messageType.Name == "Person");

    // personType.Parser. ???

}

clarification/comments

I think what you're asking is: given a schema known only at runtime via a parsed .proto, how can we deserialize the data - presumably into some runtime-only model (we should not assume that we have access to any generated/matching types).

最后,我想将有线二进制格式转换为人类可读的文本,请参阅 How to convert a binary message to a human readable format (e.g. json) given its .proto file at runtime?

如果有任何其他方法可以进行这种格式转换,我不一定需要任何模型来反序列化和从中反序列化 serialization/formatting 到可读文本。 这只是看起来最有可能实际工作的工作流程,至少从我在网上找到的内容来看是这样。

问题在于,这种基于反射的 ProtoBuffers 处理所需的运行时功能在不同语言之间是不同的(甚至如您所指出的一种语言的库)。很难估计可能解决方案的丑陋程度,因为它总是来自非常详细的方面,例如需要编译模式,需要调用 protoc,无法从 DescriptorProto 获取解析器,在 C# 中没有可用的某些功能,等等

这就是为什么我要尝试实施不同的解决方案,例如这个问题中的解决方案,以查看该特定道路是否被阻挡,如果被阻挡,是否被墙或山所阻挡。

我认为您要问的是:给定一个仅在 运行 时间通过解析的 .proto 已知的模式,我们如何反序列化数据 - 大概是一些 运行 时间模型(我们不应该假设我们可以访问任何 generated/matching 类型)。

如果这是正确的,那么这是 protobuf-net 当前未实现的功能。您 可以 将数据作为 Extensible 子类读取,然后通过扩展 API 手动访问字段,但这会很困难、很慢而且很难看。另一种选择可能是在 运行 时间用 C# 生成匹配模型,编译它,然后 运行 它——但这又是:复杂而且不一定特别快(除非你可以缓存类型等) .还有一个 reader API,如果你想逐个字段地遍历一个 protobuf 流,并且对于每个:与你持有的模式进行比较,然后做......一些事情与价值观。

最终,我还没有完成发现工作来想象这种情况下可用和有用 API,更不用说实施了。我乐于接受建议,但可能是 GitHub 个问题。