Sagen wir, ich serialisieren möchten, deserialisieren dann eine Dezimalzahl protobuf-net mit:Protobuf-net (de) Serialisierung von Dezimalstellen wirft, wenn benutzerdefinierte Dezimalzahl proto Vertrag mit (C#/C++ Interop)
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);
}
Es funktioniert gut . Protobuf-net intern verwendet die folgende Darstellung für Dezimalzahlen (vgl 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
}
Jetzt sagen, dass ich einen vermeintlich gleichwertigen proto Auftrag durch Code definieren:
[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;
}
... dann kann ich‘ t serialisieren Sie eine decimal
und erhalten Sie eine MyDecimal
zurück, noch eine MyDecimal
serialisieren und erhalten Sie eine decimal
zurück.
Von decimal
-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);
}
Von 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);
}
Fehle ich etwas hier?
Ich arbeite an einer C++ - Anwendung, die mit einem C# One über Protokollpuffer kommunizieren muss und kann nicht herausfinden, warum dezimale Deserialisierungen fehlschlagen.
Danke für die Antwort. All dies macht Sinn. Einige Kommentare: 1. Wir senden keine nackten Dezimalzahlen, wir verwenden sie in DTO. 2. Ja, meine Probe zeigt nicht ganz das Problem, das ich hatte; Tatsächlich fand ich heraus, dass die Serialisierung/Deserialisierung eines DecimalWrapper, der eine Dezimalstelle zu/von einem MyDecimalWrapper mit einem MyDecimal enthielt, wie erwartet funktionierte. 3. In meinem Fall habe ich eine Dezimalstelle in C++, die als eine C# kompatible lo/hi/signscale ausgedrückt werden kann; das Protobuf-Netz-Dezimalsystem sah wie ein guter Vertrag aus. –
4. Das Problem scheint durch die Tatsache verursacht zu werden, dass bcl.proto decimal mit einer 'sint32' SignScale definiert wurde, und dass protobuf-net ein' uint32' zum/vom Stream schrieb/las. Wenn die Serialisierung in C++ erfolgte (Schreiben von 'sint32'), dann erzeugt die Art, wie protobuf-net sie liest, einen ungültigen Wert. Ich bin nicht einmal sicher, wie man 'sint32' Werte in C# behandelt. –
@RomainVerdier ah, 'sint32' vs' uint32' ... verdammt, das ist ein Schmerz. Die Zick-Zack-Kodierung ist einfach genug, aber wenn ich den Vertrag und Code verschiedene Dinge sagen lasse, dann ist das ärgerlich –