Qual è il modo migliore per rappresentare System.Decimal nel buffer protocollo?
-
21-08-2019 - |
Domanda
A seguito di questa domanda , quale sarebbe il modo migliore per rappresentare un oggetto System.Decimal in un buffer di protocollo?
Soluzione
Bene, protobuf-net sarà semplicemente gestire questo per voi; Si corre al largo delle proprietà dei tipi, e ha il pieno supporto per decimal
. Dal momento che non esiste un modo diretto di esprimere <=> in proto, non sarà (al momento) generano una proprietà <=> da un file "Proto", ma sarebbe un bel tweak per riconoscere alcuni tipo comune ( "BCL .Decimal" o simili) e interpretarlo come decimale.
Per quanto riguarda lo rappresenta - ho avuto un documento di discussione su questo (ora fuori moda ho il sospetto) nella zona wiki protobuf-net; v'è ora una versione funzionante in protobuf-net che semplicemente lo fa per te.
Non c'è dubbio che Jon ed io martello questo fuori più tardi oggi ;-p
La versione protobuf-net di questo (in Proto) è qualcosa di simile (da qui ):
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
}
Altri suggerimenti
Marc e ho piani molto vaghi per trovare una libreria "messaggio comune PB" in modo tale che si può rappresentare tipi abbastanza comuni (data / ora e decimali balzando immediatamente in mente) in un modo comune, con conversioni disponibili in. NET e Java (e qualsiasi altra cosa a chiunque voglia contribuire).
Se sei felice di attenersi a .NET, e siete alla ricerca di compattezza, mi piacerebbe eventualmente andare con qualcosa come:
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;
}
Il segno può semplicemente essere rappresentato dal segno di exponent_and_sign, con l'esponente di essere il valore assoluto.
Fare due parti della mantissa opzionale significa che 0 è rappresentato molto compatto (ma ancora differenziazione tra 0m e 0.0000m ecc). exponent_and_sign potrebbe essere facoltativo e se volevamo.
Non so sul progetto di Marc, ma nella mia porta genero classi parziali, in modo da poter mettere la conversione tra uno System.Decimal e Protobuf.Common.Decimal (o qualsiasi altra cosa) nella classe parziale.
Ho messo insieme un patch per protobuf-csharp porte con ganci che genera le classi protobuf con decimale nativa e le strutture DateTime. formato Wire saggio, essi sono rappresentati da due messaggi proto "built-in".
A leggermente più semplice per implementare approccio di Jon o Marc consiste nel memorizzare come 4 sint32
valori che mappa banalmente all'uscita di Decimal.GetBits () .
Il file proto sarà simile a:
message ProtoDecimal {
sint32 v1 = 1;
sint32 v2 = 2;
sint32 v3 = 3;
sint32 v4 = 4;
}
E il convertitore sarà:
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]
}
}
Questo potrebbe non essere così semplice in altre lingue, ma se hai solo di indirizzare C #, allora ci vorrà lo stesso massimo di 16 byte che l'altro approccio (anche se valori come 0 potrebbe non essere memorizzato come compatto - I non so abbastanza circa gli intricati dettagli di come protobuf negozi interi), pur essendo molto più chiaro per i programmatori muto-muti come me :)
Ovviamente si dovrà correre i cavalli se si desidera le prestazioni di prova ma dubito c'è molto in esso.