使用自定义十进制原型契约(C# C互 *** 作)时,使用Protobuf-net(de)序列化小数

使用自定义十进制原型契约(C# C互 *** 作)时,使用Protobuf-net(de)序列化小数,第1张

概述假设我想序列化,然后使用protobuf-net反序列化小数: const decimal originalDecimal = 1.6641007661819458m;using (var memoryStream = new MemoryStream()){ Serializer.Serialize(memoryStream, originalDecimal); memory 假设我想序列化,然后使用protobuf-net反序列化小数:
const decimal originalDecimal = 1.6641007661819458m;using (var memoryStream = new MemoryStream()){    Serializer.Serialize(memoryStream,originalDecimal);    memoryStream.position = 0;    var deserializedDecimal = Serializer.Deserialize<decimal>(memoryStream);    Assert.AreEqual(originalDecimal,deserializedDecimal);}

它工作正常. Protobuf-net内部使用以下小数表示(参见Bcl.proto):

message Decimal {  optional uint64 lo = 1; // the first 64 bits of the underlying value  optional uint32 hi = 2; // the last 32 bis of the underlying value  optional sint32 signScale = 3; // the number of decimal digits,and the sign}

现在说我用代码定义了一个假定的等价原型合约:

[ProtoContract]public class MyDecimal{    [ProtoMember(1,Isrequired = false)]    public ulong Lo;    [ProtoMember(2,Isrequired = false)]    public uint Hi;    [ProtoMember(3,Isrequired = false)]    public int SignScale;}

…然后我无法序列化小数并返回MyDecimal,也不能序列化MyDecimal并返回小数.

从十进制到MyDecimal:

const decimal originalDecimal = 1.6641007661819458m;using (var memoryStream = new MemoryStream()){    Serializer.Serialize(memoryStream,originalDecimal);    memoryStream.position = 0;    // following line throws a InvalID wire-type ProtoException    Serializer.Deserialize<MyDecimal>(memoryStream);}

从MyDecimal到decimal:

var myDecimal = new MyDecimal{    Lo = 0x003b1ee886632642,Hi = 0x00000000,SignScale = 0x00000020,};using (var memoryStream = new MemoryStream()){    Serializer.Serialize(memoryStream,myDecimal);    memoryStream.position = 0;    // following line throws a InvalID wire-type ProtoException    Serializer.Deserialize<decimal>(memoryStream);}

我在这里错过了什么吗?

我正在研究一个需要通过协议缓冲区与C#进行通信的C应用程序,并且无法确定为什么十进制反序列化失败.

解决方法 这是“它是一个对象还是一个裸值?”的边缘情况.你不能只是在protobuf中序列化一个int – 你需要一个包装器对象.因此,对于裸值,它假装该值实际上是假设包装器对象的字段1.但是,在十进制的情况下,这有点棘手 – 因为十进制实际上编码就好像它是一个对象.因此技术上十进制可以写成一个裸值…但是:它看起来不是(它包装它) – 我怀疑在这个阶段纠正它是个好主意.

基本上,如果不是序列化裸值,则序列化具有值的对象,这将更加可靠地工作.它也可以更有效地工作(protobuf-net寻找它所知道的类型,裸值非常有后备的情况).例如:

[ProtoContract]class DecimalWrapper {    [ProtoMember(1)]    public decimal Value { get; set; }}[ProtoContract]class MyDecimalWrapper {    [ProtoMember(1)]    public MyDecimal Value { get; set; }}

如果我们序列化它们,它们是100%可互换的:

const decimal originalDecimal = 1.6641007661819458m;using (var memoryStream = new MemoryStream()){    var obj = new DecimalWrapper { Value = originalDecimal };    Serializer.Serialize(memoryStream,obj);    // or,as it happens (see text) - this is equal to    // Serializer.Serialize(memoryStream,originalDecimal);    memoryStream.position = 0;    var obj2 = Serializer.Deserialize<MyDecimalWrapper>(memoryStream);    Console.Writeline("{0},{1},{2}",obj2.Value.Lo,obj2.Value.Hi,obj2.Value.SignScale);    // ^^^ 16641007661819458,32    memoryStream.SetLength(0);    Serializer.Serialize(memoryStream,obj2);    memoryStream.position = 0;    var obj3 = Serializer.Deserialize<DecimalWrapper>(memoryStream);    bool eq = obj3.Value == obj.Value; // True}

实际上,因为protobuf-net假装有一个对象,所以说Serialize< decimal>也是如此.将与Serialize< MyDecimalWrapper> 100%兼容,但为了您自己的理智,可能更容易坚持一个简单的“总是序列化DTO实例”的方法,而不是必须认为“这是一个DTO?或者它是一个赤裸裸的价值?“

最后的想法是:如果你使用互 *** 作,我建议避免使用十进制,因为protobuf规范中没有定义,并且不同的平台通常具有不同的“十进制”类型的含义. protobuf-net发明了一个含义,主要是为了让protobuf-net能够往返(自身)更广泛的DTO,但将该值解析为任意平台可能会很尴尬.当跨平台工作并使用小数时,我建议考虑像double / float这样的东西,或者通过long / ulong或者甚至只是字符串的一些固定精度.

总结

以上是内存溢出为你收集整理的使用自定义十进制原型契约(C#/ C互 *** 作)时,使用Protobuf-net(de)序列化小数全部内容,希望文章能够帮你解决使用自定义十进制原型契约(C#/ C互 *** 作)时,使用Protobuf-net(de)序列化小数所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1252945.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存