11

我有一个使用 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}
}

当 Value = 0 时,它不会被 protobuf-net 序列化,但在反序列化过程中,构造函数会强制 Value 为 1(并且 protobuf-net 不会更改此值)。

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

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

但是,由于这个特性我们已经遇到了错误,我们想为整个模型强制使用 protobuf-net ,而不是标记每个属性。

是否可以?

4

1 回答 1

9

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

为避免改变依赖于 v1 行为的代码行为(通过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));

我将来可能会考虑的另一种方法是允许装配级属性。这对于使用“预编译器”(例如,针对移动设备或 WinRT)的任何人特别有帮助 - 所以(只是大声思考):

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

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

于 2012-09-06T08:58:43.613 回答