为什么 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,它不希望创建新列表。但同样 - 其中大部分不适用于数组,因为数组总是需要重新分配以调整它们的大小。
我有一个 属性 依赖于对象的有效状态。我在创建对象期间或在 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,它不希望创建新列表。但同样 - 其中大部分不适用于数组,因为数组总是需要重新分配以调整它们的大小。