Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Proto-Buf中使用bool类型_C#_Protobuf Net - Fatal编程技术网

C# 在Proto-Buf中使用bool类型

C# 在Proto-Buf中使用bool类型,c#,protobuf-net,C#,Protobuf Net,我在我的应用程序中使用protobuf net进行序列化/反序列化。我面临一个问题 [ProtoContract()] ClsTest { private bool _isPeriodic [ProtoMember(1)] public bool IsPeriodic { get { return _isPeriodic; } set {

我在我的应用程序中使用protobuf net进行序列化/反序列化。我面临一个问题

[ProtoContract()]
ClsTest
{
    private bool _isPeriodic

    [ProtoMember(1)]
    public bool IsPeriodic
    {
        get
        {
             return _isPeriodic;
        }

        set
        {
            isPeriodic = value;
        }
   }

}
我在collection对象中使用这个类


序列化过程工作正常,但在反序列化之后,属性IsPeriodic的值默认为true,尽管在某些情况下为false。有人能帮我吗?

以下对我来说很好:

[ProtoContract]
class ClsTest
{
    [ProtoMember(1)]
    public bool IsPeriodic { get; set; }
}
反序列化:

   // stream is a NetworkStream object

   ClsTest clsTestObj = Serializer.DeserializeWithLengthPrefix<ClsTest>(stream, PrefixStyle.Fixed32);
   bool value = clsTestObj.IsPeriodic;
//流是NetworkStream对象
ClsTest clsTestObj=序列化程序.DeserializeWithLengthPrefix(stream,PrefixStyle.Fixed32);
bool值=clsTestObj.IsPeriodic;

我猜您的代码正在将默认
实例的
IsPeriodic
设置为
true
,可能:

private bool _isPeriodic = true;
或者,在构造函数中,您有:

_isPeriodic = true; // or IsPeriodic = true
基本上,存在一个隐式默认值(遵循protobuf语言指南),其中bool假定默认值为
false
。它不发送被认为是默认的数据。如果此默认值不正确,请告诉它:

[ProtoMember(1), DefaultValue(true)]
或者IIRC您可以尝试将
IsRequired
设置为
true

[ProtoMember(1, IsRequired = true)]
还有一些其他方法可以告诉它始终发送值:

private bool ShouldSerializeIsPeriodic() { return true;}
(它使用的模式与core.NET支持的
PropertyGrid
XmlSerializer
PropertyDescriptor
等模式相同-我不是在发明随机模式)

请注意,在“v2”中,我做了两个进一步的更改以帮助消除这种奇怪现象:

  • 您可以选择绕过构造函数(WCF样式)
  • 新的元模型提供了另一种决定是否假设默认值的方法

我发现使用protobuf-net处理bool和enum类型有一些技巧。 关于bool和enum类型的默认值的第一个问题: 以下是我的Linq代码片段:

[ProtoContract]
public class MyOption
{
    [ProtoMember(2)]
    public View m_printListView = View.Details;   (A)
    [ProtoMember(5) ]
    public bool m_bool = true ;                   (B)
}

void Main()
{
    string fname = @"D:/test.dat";
    if (File.Exists(fname) )
    {
        File.Delete(fname);
    }
    using(FileStream fs=  new FileStream(fname, FileMode.OpenOrCreate, FileAccess.Write) )
    {
        MyOption opt = new MyOption();
        opt.m_printListView = View.LargeIcon; // (1)
        opt.m_bool = false;                   // (2)

        Serializer.SerializeWithLengthPrefix(fs, opt, PrefixStyle.Fixed32);
    }
    using(FileStream fs=  new FileStream(@"D:/test.dat", FileMode.Open, FileAccess.Read) )
    {
        MyOption opt;
        opt = Serializer.DeserializeWithLengthPrefix<MyOption>(fs, PrefixStyle.Fixed32);
        Console.WriteLine(opt.m_printListView);
        Console.WriteLine(opt.m_bool);
    }
}
请注意,在(A)和(B)中,我将默认值设置为View.Details和true。 在(1)和(2)中,在proto buf序列化和 反序列化,我们得到了错误的值

原因是:对于bool值,默认值为false,根据proto buf的设计原则,它将在可能的情况下节省空间,因此默认值不会保存在文件中,只保存一个标志,指示应使用默认值(我猜,未验证)

反序列化时,首先调用默认构造函数,在CLR运行时,行(B)实际上是默认构造函数的一部分,然后启动proto buf反序列化过程,发现成员m_bool有一个默认值标志,然后使用默认值false设置m_bool,覆盖(B)处的默认值

对于枚举类型,原因类似,在上面的示例视图中。LargeIcon是默认值,其数值为0(由反射验证)

要使用bool和enum成员的DefaultValueAttribute修复它,请执行以下操作:

[ProtoContract]
public class MyOption
{
    [ProtoMember(2), DefaultValue(View.Details)]
    public View m_printListView = View.Details;   (A)
    [ProtoMember(5), DefaultValue(true) ]
    public bool m_bool = true ;                   (B)
}
对于枚举类型,还有其他问题: 第一个是所有枚举数都应该有不同的值,否则proto buf在序列化时会抛出异常,例如System.Drawing.RotateFlip枚举类型有以下定义:

    public enum RotateFlipType
{
    Rotate180FlipNone = 2,
    Rotate180FlipX = 6,
    Rotate180FlipXY = 0,
    Rotate180FlipY = 4,
    Rotate270FlipNone = 3,
    Rotate270FlipX = 7,
    Rotate270FlipXY = 1,
    Rotate270FlipY = 5,
    Rotate90FlipNone = 1,
    Rotate90FlipX = 5,
    Rotate90FlipXY = 3,
    Rotate90FlipY = 7,
    RotateNoneFlipNone = 0,
    RotateNoneFlipX = 4,
    RotateNoneFlipXY = 2,
    RotateNoneFlipY = 6
}
从图像处理的角度来看,RotateNoneFlipNone和Rotate180FlipXY具有相同的效果,因此它们具有相同的效果 相同的基础值,这是一个合理的设计,但是,这样的枚举不能与proto buf一起工作:

    The enum System.Drawing.RotateFlipType has conflicting values RotateNoneFlipNone and RotateNoneFlipNone
Serializer.ThrowInner (Exception exception)
  at ProtoBuf.Serializer.ThrowInner(Exception exception)
  at ProtoBuf.Serializer.Serialize[T](Stream destination, T instance)
  at ProtoBuf.Serializer.SerializeWithLengthPrefix[T](Stream destination, T instance, PrefixStyle style, Int32 tag)
我的解决方法是创建自己的枚举,并在我的\u RotateLipType和System.Drawing.RotateLipType之间使用一对一映射。proto buf将仅序列化My_RotateFlipType

public enum RotateFlipType              public enum My_RotateFlipType
{                                       {
    Rotate180FlipNone = 2,                  Rotate180FlipNone,
    Rotate180FlipX = 6,                     Rotate180FlipX,
    Rotate180FlipXY = 0,                    Rotate180FlipXY,
    Rotate180FlipY = 4,                     Rotate180FlipY,
    Rotate270FlipNone = 3,                  Rotate270FlipNone,
    Rotate270FlipX = 7,                     Rotate270FlipX,
    Rotate270FlipXY = 1,                    Rotate270FlipXY,
    Rotate270FlipY = 5,                     Rotate270FlipY,
    Rotate90FlipNone = 1,                   Rotate90FlipNone,
    Rotate90FlipX = 5,                      Rotate90FlipX,
    Rotate90FlipXY = 3,                     Rotate90FlipXY,
    Rotate90FlipY = 7,                      Rotate90FlipY,
    RotateNoneFlipNone = 0,                 RotateNoneFlipNone,
    RotateNoneFlipX = 4,                    RotateNoneFlipX,
    RotateNoneFlipXY = 2,                   RotateNoneFlipXY,
    RotateNoneFlipY = 6                     RotateNoneFlipY
}                                       }
为了避免手动同步两个数据成员,我使用ProtoBeforeSerialization和OnProtoAfterDeserialization功能将其自动化:

[ProtoAfterDeserialization()]
public void OnProtoAfterDeserialization()
{
    Console.WriteLine("called OnProtoAfterDeserialization");
    bool ret = Enum.TryParse(m_rotate.ToString(), out m_rotate_protobuf);
}

[ProtoBeforeSerialization()]
public void OnProtoBeforeSerialization()
{
    Console.WriteLine("called OnProtoBeforeSerialization");
    bool ret = Enum.TryParse(m_rotate_protobuf.ToString(), out m_rotate);
}
关于枚举的第二个问题是0值枚举数。如果枚举没有值为0的枚举数,则 protobuf很容易在运行时抛出异常

使用protobuf net时,我将遵循以下规则: 1.每当默认构造函数设置默认值以外的值时,请使用DefaultValueAttribute。
2.对于系统或第三方枚举类型,在将其添加到protobuf之前,请使用reflector(静态)或linq(运行时)检查它是否存在上述问题。如果发生冲突,请使用上述解决方法。

我遇到了类似的问题,默认为
true
bool
成员没有从配置文件中读取其值

[ProtoMember(1, IsRequired=true), DefaultValue(true)]
public bool IsPeriodic
...
[ProtoMember(1, IsRequired=true), DefaultValue(true)]
public bool IsPeriodic
...