继this问题后,在协议缓冲区中表示System.Decimal对象的最佳方法是什么?
答案 0 :(得分:7)
好吧,protobuf-net将为您处理这个问题;它运行类型的属性,并完全支持decimal
。由于没有直接的方法在proto中表达decimal
,因此它不会(当前)从“.proto”文件生成decimal
属性,但是识别一些常见内容将是一个很好的调整输入(“BCL.Decimal”或类似)并将其解释为十进制。
至于代表它 - 我在protobuf-net wiki区域有一个discussion document(我怀疑已经过时了);现在有一个protobuf-net的工作版本,它只是为你做的。
毫无疑问,乔恩和我今天晚些时候会更多地解决这个问题;-p
这个(在.proto中)的protobuf-net版本就像(来自here):
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
}
答案 1 :(得分:5)
Marc和我有一个非常模糊的计划,想出一个“常见的PB消息”库,这样你就可以用一种常见的方式表示非常常见的类型(日期/时间和小数现象),转换可用。 NET和Java(以及其他任何想要贡献的东西)。
如果你很乐意坚持.NET,并且你正在寻找紧凑性,我可能会选择以下内容:
message Decimal {
// 96-bit mantissa broken into two chunks
optional uint64 mantissa_msb = 1;
optional uint32 mantissa_lsb = 2;
required sint32 exponent_and_sign = 3;
}
符号可以用exponent_and_sign的符号表示,指数是绝对值。
使尾数的两个部分都可选意味着0表示非常紧凑(但仍然区分0m和0.0000m等)。如果我们真的想要,exponent_and_sign也可以是可选的。
我不知道Marc的项目,但是在我的端口中我生成了部分类,所以你可以将System.Decimal和Protobuf.Common.Decimal(或其他)之间的转换放入部分类中。
答案 2 :(得分:0)
我为protobuf-csharp-port添加了一个带有钩子的补丁,它使用原生的Decimal和DateTime结构生成protobuf类。有线格式,它们由两个“内置”原型消息代表。
答案 3 :(得分:0)
比Jon或Marc的实现方法更简单的方法是将其存储为4个sint32
值,该值方便地微不足道地映射到Decimal.GetBits()的输出。
原始文件如下:
message ProtoDecimal {
sint32 v1 = 1;
sint32 v2 = 2;
sint32 v3 = 3;
sint32 v4 = 4;
}
转换器将是:
public decimal ConvertToDecimal(AbideDecimal value)
{
return new decimal(new int[] { value.V1, value.V2, value.V3, value.V4 });
}
public ProtoDecimal ConvertFromDecimal(decimal value)
{
var bits = decimal.GetBits(value);
return new ProtoDecimal
{
V1 = bits[0],
V2 = bits[1],
V3 = bits[2],
V4 = bits[3]
}
}
这在其他语言中可能不那么简单,但是如果您只需要定位C#,则它将占用与其他方法相同的最大16个字节(尽管像0这样的值可能不会紧凑存储-我对protobuf如何存储int的复杂细节知之甚少,而对于像我这样的傻瓜程序员来说却要清晰得多:)
很显然,如果要测试性能,则必须race the horses,但我怀疑其中是否有很多内容。
答案 4 :(得分:0)
当您知道小数位数有限时,可以使用最小的单位作为整数值。例如,在处理货币时,不需要十进制类型,而是可以定义使用单位美分。然后,无论使用哪种货币,值均为2
的整数都将引用0.02
。