强制protobuf-net序列化所有默认值

ghu*_*sse 10 c# serialization protobuf-net

我有一个使用protobuf-net序列化/反序列化的复杂模型,我们有几个错误,这个"功能"没有序列化默认值.

例:

[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}
}
Run Code Online (Sandbox Code Playgroud)

当Value = 0时,它不是由protobuf-net序列化的,但在反序列化期间,构造函数强制Value为1(并且protobuf-net不会改变它).

为了使它工作,我需要强制protobuf-net序列化值,用:

  // Works fine
  [DataMember(Order = 1, IsRequired = true)]
  public double Value {get; set}
Run Code Online (Sandbox Code Playgroud)

但是,由于我们已经因为这个功能而出现了错误,我们希望为整个模型强制使用protobuf-net ,而不是标记每个属性.

可能吗?

Mar*_*ell 9

是的,完全支持此功能.实际上,如果我被迫承认v1中的错误设计决策,隐式零默认值将是其中之一 - 但为了向后兼容,默认情况下会保留该行为.您正在寻找的是RuntimeTypeModel.UseImplicitZeroDefaults,true默认情况下.

为避免更改依赖于v1行为(via Serilaizer.*)的代码行为,您无法默认模型上更改此功能,因此您需要做的是:

  1. 定义您自己的模型/序列化程序实例
  2. 设置UseImplicitZeroDefaults = false,之前使用它
  3. 在序列化/反序列化代码中,使用此实例而不是 Serializer.*

例如:

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));
Run Code Online (Sandbox Code Playgroud)

我将来可能考虑的另一种方法是允许汇编级属性; 这对于使用"预编译器"(例如,瞄准移动设备或WinRT)的人来说尤其有用 - 所以(只是大声思考):

// this feature ***does not currently exist***
[assembly:ProtoDefaults(UseImplicitZeroDefaults=false, SkipConstructor=true)]
Run Code Online (Sandbox Code Playgroud)

然后将适用于该程序集中的所有类型.只是一个想法.另一个明显的优点是它可以使用经典Serializer.*API的代码.