【问题标题】:De-serializing Protoc Generated C# class results in data getting wiped out反序列化 Protoc 生成的 C# 类会导致数据被清除
【发布时间】:2021-08-14 01:35:47
【问题描述】:

当我反序列化 protoc 生成的 C# 对象时,我设置的属性会被清除。任何人都可以帮忙吗?我正在使用Newtonsoft.Json nuget 包。 proto 文件(测试 C# 解决方案中的“SimplifiedProto.proto”)有什么问题吗?

proto文件内容

syntax = "proto3";

option java_multiple_files = true;
option java_outer_classname = "SpreadProtos";

option csharp_namespace = "SpreadProtos";

message Parameters {
    oneof instanceOrGroup {
       string Instance = 10;
       string Algo = 60;
    }
}

message Spread {
    Parameters parmeters = 10;
}
 
message Order {
    double minFilledPercentage = 10;
    Parameters parmeters = 30;
}
 
message Request {
    oneof newRequestOpt {
        Spread create = 5;
    }
    string clientRequestId = 100;
}

C#程序

Request request = new Request()
{
    ClientRequestId = "someId",
    Create = new Spread()
    {
        Parmeters = new Parameters()
        {
            Instance = "someInstanceValue"
        }
    }
};

string jsonConvertStr = JsonConvert.SerializeObject(request);
Request requestJsonConvert = JsonConvert.DeserializeObject<Request>(jsonConvertStr);
//At this point the value stored in Instanc Prop is lost

谢谢 J

【问题讨论】:

  • 明确一点:您是说该值没有正确地通过 JSON.NET 进行往返吗? JSON 字符串在这里是什么样子的? (附带说明:这个 DTO 是为 protobuf 设计的;如果它不适用于 JSON.NET:那可能不是一个巨大的设计目标)
  • 嗨,马克,这是正确的。我希望我可以提供使用“protoc.exe”生成的 C# 类,但我无法在此处附加它。但是如果您要使用该工具生成它,并按照上面的代码设置值,请将其序列化,然后反序列化,“ClientRequestId”为空。
  • 您确定ClientRequestId 受到影响吗?这是Request 的属性。您之前在Instance 下谈论过价值,这是一个非常 不同的主张。我会期望 ClientRequestId 工作正常 - 生成的代码只是一个支持字段和属性 getter 和 setter(带有 null 检查),没有任何条件序列化等
  • 对不起,我的意思是“实例”.. 一旦你反序列化,它就消失了.. 如果你熟悉 proto 编译器(protoc),你可以生成类自己尝试。我无法在此处附加该课程..
  • 我很熟悉——其实你可以使用我这里的工具生成代码protogen.marcgravell.com——只需将下拉列表改为CSharpProtoc即可获取protoc版本。就个人而言,我更喜欢 protobuf-net 的方法,但我有偏见:)

标签: c# json json.net protocol-buffers proto


【解决方案1】:

最终,这里的问题是生成的代码不包括“条件序列化”,这意味着它在序列化时将两个字符串都写为""(而不是省略无效的)。你可以在这里看到:

    /// <summary>Field number for the "Instance" field.</summary>
    public const int InstanceFieldNumber = 10;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Instance {
      get { return instanceOrGroupCase_ == InstanceOrGroupOneofCase.Instance ? (string) instanceOrGroup_ : ""; }
      set {
        instanceOrGroup_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        instanceOrGroupCase_ = InstanceOrGroupOneofCase.Instance;
      }
    }

    /// <summary>Field number for the "Algo" field.</summary>
    public const int AlgoFieldNumber = 60;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Algo {
      get { return instanceOrGroupCase_ == InstanceOrGroupOneofCase.Algo ? (string) instanceOrGroup_ : ""; }
      set {
        instanceOrGroup_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        instanceOrGroupCase_ = InstanceOrGroupOneofCase.Algo;
      }
    }

反序列化时,它会两次写入字符串,这意味着:最后一个获胜,即使它擦除了值。

好消息是:它使用部分类,所以:你可能可以解决这个问题!

在单独的文件中尝试(未经测试):

namespace SpreadProtos {
    partial class Parameters {
        public bool ShouldSerializeInstance() =>
            instanceOrGroupCase_ == InstanceOrGroupOneofCase.Instance;
        public bool ShouldSerializeAlgo() =>
            instanceOrGroupCase_ == InstanceOrGroupOneofCase.Algo;
    }
}

ShouldSerialize*() 模式是许多序列化程序认可的众所周知的方法,包括 (IIRC) JSON.NET;结果应该是只有活动字段被序列化,这应该防止它在反序列化期间破坏东西。

【讨论】:

  • 谢谢马克。我要试试这个然后回来。我想知道为什么 Protoc 没有解决像这样的明显问题。
  • @Zest4Quest 正如我所说:protoc 主要关注 itself 将如何序列化(到 protobuf 或 json),而不是 external 工具将如何序列化做它; FWIW,正如我所说:protobuf-net 得到了一些更有用的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多