I have a complex model serialized/deserialized with protobuf-net, and we had several bugs with this "feature" of not serializing default values.
Example:
[DataContract]
class Foo{
public Foo(){
// Value forced by constructor
this.Value = 1;
}
// Buggy, when Value is set to zero
[DataMember(Order = 1)]
public double Value {get; set}
}
When Value = 0, it is not serialized by protobuf-net, but during deserialization, the constructor forces Value to 1 (and protobuf-net do not change this).
In order to make it work, I need to force protobuf-net to serialize values, with:
// Works fine
[DataMember(Order = 1, IsRequired = true)]
public double Value {get; set}
But, as we already got bugs because of this feature, we'd like to force protobuf-net for the whole model, instead of marking every property.
Is it possible?
Yes, this feature is fully supported. Actually, if I was forced to admit to bad design decisions in v1, the implicit-zero-defaults would be one of them - but for backwards compatibility the behaviour is retained by default. What you are looking for is RuntimeTypeModel.UseImplicitZeroDefaults
, which is true
by default.
To avoid changing the behaviour of code relying on v1 behaviour (via Serilaizer.*
), you cannot change this feature on the default model, so what you need to do is:
UseImplicitZeroDefaults = false
, before using itSerializer.*
for example:
private static readonly RuntimeTypeModel serializer;
static MyType() { // your type-initializer for class MyType
serializer = TypeModel.Create();
serializer.UseImplicitZeroDefaults = false;
}
... then when needed:
serializer.Serialize(stream, obj);
...
ObjType obj = (ObjType)serializer.Deserialize(stream, null, typeof(ObjType));
Another approach I could perhaps consider in the future is allowing for assembly-level attributes; this would help in particular for anyone using "precompiler" (for example, targeting mobile devices or WinRT) - so (just thinking aloud):
// this feature ***does not currently exist***
[assembly:ProtoDefaults(UseImplicitZeroDefaults=false, SkipConstructor=true)]
which would then apply to all types in that assembly. Just a thought. Another obvious advantage is that it would work with code that uses the classic Serializer.*
API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With