为什么 protobuf-net 在反序列化过程中调用了 属性 的 getter 但尚未调用 setter

Why does protobuf-net calls the getter of a property during deserialization but setter was not called yet

我有一个 属性 依赖于对象的有效状态。我在创建对象期间或在 OnDeserialized 函数中确保这一点。

现在我在 protobuf-net 反序列化过程中遇到了一个神奇的异常,因为该对象尚未生效,因为 属性 的 getter 在反序列化过程中已经被调用。既没有调用 setter 也没有调用 OnDeserialized 方法(调用了 OnDeserializing!)

我确实从 DataContractSerializer 转换而来,所以 SkipConstructor 是为了确保相同的行为(我不想删除它)。代码看起来大致像这样:

[ProtoContract(SkipConstructor = true, EnumPassthru = true)]
public class MyClass
{
    [OnSerializing]
    [ProtoBeforeSerialization]
    private void OnSerializing(StreamingContext c)
    {
        // first in here
    }

    [OnSerialized]
    [ProtoAfterSerialization]
    private void OnSerialized(StreamingContext c)
    {
        //
    }

    [ProtoMember(1)]
    private AnotherClass[] NetworkValues
    {
        get {   /* Why here after OnSerializing? */ }
        set { }
    }
}

我不明白。 getter 在反序列化过程中有什么用?

两个原因

首先:Protocol Buffers 本质上将反序列化定义为 "merge" - 允许将数据合并到现有对象中,并允许将两个字节流连接起来作为合并。因此,因为它假定它正在进行合并,默认情况下 protobuf-net 正在做的事情,在列表的情况下,是

  • 获取现有列表,如果有的话;否则创建一个新列表
  • 向此列表添加任何新元素(已有的或新的)
  • 如果列表已更改,则将其分配给 属性

可以通过在 [ProtoMember] 上将 OverwriteList 属性 设置为 true 来覆盖此行为,这使得它始终将 属性 视为新的列表(因此:先前存在的项目将丢失)


其次,该库需要支持一种非常常见的模式——只读列表访问器。这 并不是 数组真正需要的,但大部分代码都适用于两者 - 但本质上:

private readonly List<AnotherClass> _networkValues = new List<AnotherClass>();
[ProtoMember(1)]
public List<AnotherClass> NetworkValues => _networkValues;

在这种情况下,唯一 库获取列表的机制是:获取。

附带说明:图书馆还希望在这种情况下避免不必要的列表分配,所以即使一个setter,它不希望创建新列表。但同样 - 其中大部分不适用于数组,因为数组总是需要重新分配以调整它们的大小。