¿Cuál es la mejor manera de representar en System.Decimal Protocol Buffers?
-
21-08-2019 - |
Solución
Bueno, protobuf-net simplemente se encargará de esto para usted; Se ejecuta fuera de las propiedades de los tipos, y tiene soporte completo para decimal
. Puesto que no hay una forma directa de expresar <=> en proto, no va (en la actualidad) generar una propiedad <=> desde un archivo "Proto", pero sería un buen pellizco de reconocer algún tipo común ( "BCL .Decimal" o similar) e interpretarla como decimal.
En cuanto a representarla - tuve una documento de discusión en este (ahora fuera de fecha sospecho) en la zona wiki-protobuf red; ahora hay una versión de trabajo en protobuf-red que simplemente lo hace por usted.
No hay duda de Jon y yo martillarán esto más tarde hoy -P
La versión de protobuf neto de esto (en .proto) es algo así como (de aquí ):
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
}
Otros consejos
Marc y tengo planes muy vagas de subir con una biblioteca "mensaje PB común" de tal manera que se puede representar tipos muy comunes (fecha / hora y decimales que salte inmediatamente a la mente) de una manera común, con las conversiones disponibles en. NET y Java (y cualquier otra cosa que nadie quiere contribuir).
Si estás dispuesto a pegarse a .NET, y que está buscando para compacidad, me gustaría ir posiblemente con algo como:
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;
}
El signo solo puede ser representado por el signo de exponent_and_sign, con el exponente siendo el valor absoluto.
Realización de las dos partes de la mantisa opcional 0 significa que está representado muy de forma compacta (pero aún así la diferenciación entre 0m y 0.0000m etc). exponent_and_sign podría ser opcional y si realmente queríamos.
No sé sobre el proyecto de Marc, pero en mi puerto genero clases parciales, por lo que puede poner la conversión entre un System.Decimal y Protobuf.Common.Decimal (o lo que sea) en la clase parcial.
Monté un parche para protobuf-CSharp puertos con ganchos que genera las clases protobuf con decimal nativa y estructuras DateTime. Formato de alambre sabia, que están representados por dos mensajes proto "built-in".
Aquí está el enlace: https://code.google.com/p/protobuf-csharp-port/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status % 20Priority% 20Milestone% 20Owner% 20Summary y GroupBy = & sort = & id = 78
Un poco más sencillo de implementar el enfoque de Jon o Marc es almacenarlo como 4 sint32
valores, que convenientemente mapas trivialmente a la salida de Decimal.GetBits () .
El archivo proto se verá así:
message ProtoDecimal {
sint32 v1 = 1;
sint32 v2 = 2;
sint32 v3 = 3;
sint32 v4 = 4;
}
Y el convertidor será:
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]
}
}
Esto podría no ser tan simple en otros idiomas, pero si sólo tiene que dirigirse a C # y luego tomará hasta el mismo máximo de 16 bytes que (aunque no se almacene como se compacta el otro enfoque valores como 0 - I no se sabe lo suficiente sobre los intrincados detalles de cómo protobuf almacena enteros), mientras que es mucho más claro para los programadores tonto-tonto como yo :)
Obviamente, tendrá que correr los caballos si quieres rendimiento de la prueba pero dudo que hay mucho en ella.