温故知新,机器人进化论之优雅处理层级嵌套的Protobuf文件(.proto)输出为C#代码

什么是Protobuf

image

简单来说,Protobuf是代码世界的“通用翻译官”

跨语言:它让C++ 的结构体能被C#读懂,就像JSON 一样,但比JSON更强大。

高性能:它传输的是二进制(0101...),比文本格式的JSON体积小得多,解析速度快10倍以上。

强契约:通过.proto文件定义数据结构,一旦定义好,类型就是安全的。

场景重现

假设我们的 C++ 工程目录结构如下,不仅有子文件夹,还有跨文件夹的引用(Import):

MyProject/
├── proto/                  <-- 【关键】这是 Proto 的根目录
│   ├── common/             <-- 公共基础库
│   │   └── geometry.proto  <-- 定义了 Point3D 等基础类型
│   └── robot/              <-- 具体的业务模块
│       └── status.proto    <-- 这里引用了 common/geometry.proto
└── MyCSharpApp/            <-- 我们的 C# 项目
    └── MyCSharpApp.csproj

基础文件:common/geometry.proto

syntax = "proto3";
package common;
option csharp_namespace = "SmartLogistics.Common";

message Point3D {
  double x = 1;
  double y = 2;
  double z = 3;
}

业务文件:robot/status.proto

它引用了common目录下的文件

syntax = "proto3";
package robot;
option csharp_namespace = "SmartLogistics.Robot";

// 注意这里的路径:它是基于 proto/ 根目录写的
import "common/geometry.proto"; 
import "google/protobuf/timestamp.proto";

message VehicleStatus {
  string device_id = 1;
  // 直接使用了引用的类型
  common.Point3D current_location = 2; 
  google.protobuf.Timestamp last_updated = 3;
}

解决方案

1、创建一个.Net的项目,把这些文件包括在其中

image

image

2、将proto目录整体放入项目中来

image

3、给当前项目安装Nuget依赖

  • Google.Protobuf
  • Grpc.Tools (编译工具)
  • Grpc.Net.Client (可选,如果涉及 gRPC 通讯)

image

image

4、双击当前项目进入项目文件编辑

image

添加一个ItemGroup节点

<ItemGroup>
  <Protobuf Include="proto\**\*.proto"
            ProtoRoot="proto"
            GrpcServices="Client" />
</ItemGroup>

image

5、直接重新生成即可

image

这时候这些proto对应的.cs文件就在/obj目录下,如果你顺利看到你要的cs文件,说明前面的配置对了,如果没看到说明前面的配置有问题,尤其是注意刚才那个ItemGroup节点对应的路径哈。

image

6、使用

using System;
using Google.Protobuf.WellKnownTypes; // 用于 Timestamp
using SmartLogistics.Common;          // 自动生成的命名空间
using SmartLogistics.Robot;

namespace MyCSharpApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建一个复杂的嵌套对象
            var status = new VehicleStatus
            {
                DeviceId = "AGV-2026-X1",
                
                // 直接使用引用的 Point3D 类型
                CurrentLocation = new Point3D 
                { 
                    X = 10.5, 
                    Y = 20.1, 
                    Z = 0 
                },
                
                // 使用 Google 标准时间戳
                LastUpdated = Timestamp.FromDateTime(DateTime.UtcNow)
            };

            Console.WriteLine($"设备 {status.DeviceId} 位置: ({status.CurrentLocation.X}, {status.CurrentLocation.Y})");
            
            // 序列化为二进制(模拟发送给 C++ 端)
            byte[] bytes = status.ToByteArray();
            Console.WriteLine($"序列化后大小: {bytes.Length} 字节");
        }
    }
}

image

posted @ 2026-01-19 17:03  TaylorShi  阅读(0)  评论(0)    收藏  举报