在 Proto-Buf 中使用 bool 类型
我在我的应用程序中使用 protobuf-net 进行序列化/反序列化。我面临一个问题。
[ProtoContract()]
ClsTest
{
private bool _isPeriodic
[ProtoMember(1)]
public bool IsPeriodic
{
get
{
return _isPeriodic;
}
set
{
isPeriodic = value;
}
}
}
我在我的集合对象中使用这个类。
序列化过程工作正常,但反序列化后,属性 IsPeriodic 的值默认为 true,尽管在某些情况下为 false。谁能帮助我吗?
I am using protobuf-net in my application for serializaion/deserialization. I am facing an issue.
[ProtoContract()]
ClsTest
{
private bool _isPeriodic
[ProtoMember(1)]
public bool IsPeriodic
{
get
{
return _isPeriodic;
}
set
{
isPeriodic = value;
}
}
}
I am using this class in my collction object.
The serialization process workes fine, but after deserialization the Value for property IsPeriodic by default is true eventhough it was false for some cases. Can anyone help me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我遇到了类似的问题,默认为 true 的 bool 成员没有从配置文件中读取它们的值。
I had the a similar issue, where
bool
members that default totrue
were not reading their value from the config file.我发现使用 protobuf-net 处理 bool 和 enum 类型有一些技巧。
关于 bool 和 enum 类型默认值的第一个问题:
这是我的 Linq 片段代码:
现在,猜测输出。它是:
请注意,在 (A) 和 (B) 中,我将默认值设置为 View.Details 和 true。
在 (1) 和 (2) 中,在 proto-buf 序列化之后,我显式将值设置为 View.LargeIcon 和 false
反序列化,我们得到了错误的值。
原因是:对于bool值来说,默认值是false,根据proto-buf的设计原则,它会尽可能节省空间,所以默认值不会保存在文件中,只保存一个标志来指示应该使用默认值值(我猜,未验证)。
反序列化时,首先调用默认构造函数,而行(B)实际上是CLR运行时默认构造函数的一部分,然后proto-buf反序列化过程启动,发现成员m_bool有一个默认值标志,然后使用默认值 false 来设置 m_bool,这将覆盖 (B) 处的默认值。
对于enum类型的原因类似,在上面的例子中View.LargeIcon是默认值,其数值为0(通过Reflected验证)。
要使用 bool 和枚举成员的 DefaultValueAttribute 修复它:
对于枚举类型,还有其他问题:
第一个是所有枚举器应该有不同的值,否则proto-buf在序列化时会抛出异常,例如System.Drawing.RotateFlip枚举类型具有以下定义:
从图像处理的角度来看,RotateNoneFlipNone和Rotate180FlipXY具有相同的效果,所以他们有
相同的底层值,这是一个合理的设计,但是,这样的枚举不能与 proto-buf 一起使用:
我的解决方法是创建自己的枚举并在 My_RotateFlipType 和 System.Drawing.RotateFlipType 之间使用一对一映射。只有 My_RotateFlipType 会被 proto-buf 序列化。
为了避免手动同步两个数据成员,我使用 ProtoBeforeSerialization 和 OnProtoAfterDeserialization 功能来自动化它:
关于枚举的第二个问题是 0 值枚举器。如果枚举没有值为 0 的枚举器,则
protobuf 在运行时很容易抛出异常。
使用 protobuf-net 时我将遵循以下规则:
1. 每当默认构造函数设置默认值以外的值时,请使用 DefaultValueAttribute。
2.对于系统或第三方枚举类型,在将其添加到protobuf之前,请使用reflector(静态)或linq(运行时)检查它是否存在上述问题。如果发生冲突,请使用上述解决方法。
I found working with bool and enum type with protobuf-net has some tricks.
The first issue about default value for both bool and enum type:
Here's my Linq snippet code:
Now, guess the output. It's:
Note that in (A) and (B) I set default value to View.Details and true.
In (1) And (2) I explicitly set the value to View.LargeIcon and false, after proto-buf's serialization and
de-serialization, we got the wrong value.
The reason is that: for bool value, the default value is false, according to proto-buf's design principle, it will save space when possible, so default value is not saved in the file, only a flag is saved to indicate should use default value(I guess, not verified).
When de-serialization, at first the default constructor is called, and lines (B) is actually part of default constructor at CLR runtime, then the proto-buf de-serialization process kicks up, and found the member m_bool has a default value flag, then use the default value false to set m_bool, which overwrite the default value at (B).
For enum type the reason is similar, in the above example View.LargeIcon is the default value, whose numeric value is 0(verified by Reflected).
To fix it using the DefaultValueAttribute for bool and enum member:
For enum type, there're other issues:
The first one is that all the enumerator should have distinct values, otherwise proto-buf will throw exception when serialization, e.g., the System.Drawing.RotateFlip enum type has following definition:
From image processing's point, RotateNoneFlipNone and Rotate180FlipXY has the same effect, so they have
the same underlying value, it's a reasonable design, however, such a enum cannot works with proto-buf:
My workaround is to create my own enum and use one-to-one mapping between My_RotateFlipType and System.Drawing.RotateFlipType. Only My_RotateFlipType will be serialized by proto-buf.
To avoid manually sync with the two data members, I use ProtoBeforeSerialization and OnProtoAfterDeserialization feature to automate it:
The second issue about enum is the 0-value enumerator. If an enum has no enumerator with value 0, then
it's very easy for protobuf to throw exception at runtime.
I will follow the rules when working with protobuf-net:
1. Whenever the default constructor set a value other than default value, use the DefaultValueAttribute.
2. For system or third-party enum type, check it with reflector (statically) or linq (runtime) to see whether it has the above issue, before you add it to protobuf. If conflicts, use the above workaround.
以下对我来说效果很好:
反序列化:
The following works fine for me:
Deserialization:
我的猜测是,您的代码将默认
new
实例的IsPeriodic
设置为true
,也许:或者,在构造函数中您有:
基本上,有一个隐式默认值(遵循 protobuf 语言指南),其中 bool 被假定为默认值
false
。它不会发送被认为是默认的数据。如果此默认值不正确,请告诉它:或者 IIRC,您可以尝试将
IsRequired
设置为true
:并且还有其他一些方法可以告诉它始终发送值:
(它使用与核心 .NET 支持的相同模式,用于
PropertyGrid
、XmlSerializer
、PropertyDescriptor
等 - 这不是我发明随机的模式)请注意,在“v2”中,我做了两项进一步的更改,以帮助消除这种奇怪的现象:
My guess is that your code is setting
IsPeriodic
totrue
for defaultnew
instances, perhaps:or, in the constructor you have:
Basically, there is an implicit default (following the protobuf language guide) where-by bool is assumed to have a default of
false
. It doesn't send data that is believed to be the default. If this default is incorrect, tell it:or IIRC you can try setting
IsRequired
totrue
instead:and there are a few other ways of telling it to always send the value:
(which uses the same pattern that is supported by core .NET for
PropertyGrid
,XmlSerializer
,PropertyDescriptor
, etc - it isn't me inventing random patterns)Note that in "v2" I have made two further changes to help remove this oddity: