C# BinaryFormatter 字节顺序

C# BinaryFormatter bytes orde

我正在使用二进制格式化程序来序列化我的对象。 我想知道序列化字节数组中属性的顺序是什么(根据对象 class 中的属性顺序?随机?) 而如果我可以根据道具控制字节的顺序。

例如,
如果我序列化以下对象:

public class Human
{
     int Age {get;set;}
     int Weight {get; set;}
}

如果我将它序列化,字节顺序是什么意思? (前 4 个字节是否代表年龄,接下来是体重?等等......或者二进制格式化程序随机设置它)

你为什么不试试呢?让我们把你的 class

[Serializable]
public class Human
{
    public int Age {get;set;}
    public int Weight {get; set;}
}

并将其序列化,然后通过检查 HexDump

检查结果
var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using(var ms = new MemoryStream())
{
  bf.Serialize(ms, new Human{ Age = 42, Weight = -1 });
  HexDump(ms.ToArray());
}

这将给出:

00000 : 00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00  .....????.......
00016 : 00 0C 02 00 00 00 43 71 75 65 72 79 5F 6C 68 68  ......Cquery_lhh
00032 : 75 78 68 2C 20 56 65 72 73 69 6F 6E 3D 30 2E 30  uxh, Version=0.0
00048 : 2E 30 2E 30 2C 20 43 75 6C 74 75 72 65 3D 6E 65  .0.0, Culture=ne
00064 : 75 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 79  utral, PublicKey
00080 : 54 6F 6B 65 6E 3D 6E 75 6C 6C 05 01 00 00 00 0F  Token=null......
00096 : 55 73 65 72 51 75 65 72 79 2B 48 75 6D 61 6E 02  UserQuery+Human.
00112 : 00 00 00 14 3C 41 67 65 3E 6B 5F 5F 42 61 63 6B  ....<Age>k__Back
00128 : 69 6E 67 46 69 65 6C 64 17 3C 57 65 69 67 68 74  ingField.<Weight
00144 : 3E 6B 5F 5F 42 61 63 6B 69 6E 67 46 69 65 6C 64  >k__BackingField
00160 : 00 00 08 08 02 00 00 00 2A 00 00 00 FF FF FF FF  ........*...????
00176 : 0B  .

这就是 Hans 所说的复杂格式。如果你稍微眯起眼睛,你会认出一个程序集名称、class名称、字段名称(有点),如果你应用 jdweng 提供的魔法,你会注意到 4 个字节 2A 00 00 00,这将使 42(年龄)接下来的 4 个字节表示 -1(权重)。

让我们添加一个 public 字段 Name 作为第一个字段:

[Serializable]
public class Human
{
    public string Name;
    public int Age {get;set;}
    public int Weight {get; set;}   
}

让我们看看更改后的字节:

00096 : 55 73 65 72 51 75 65 72 79 2B 48 75 6D 61 6E 03  UserQuery+Human.
00112 : 00 00 00 04 4E 61 6D 65 14 3C 41 67 65 3E 6B 5F  ....Name.<Age>k_
00128 : 5F 42 61 63 6B 69 6E 67 46 69 65 6C 64 17 3C 57  _BackingField.<W
00144 : 65 69 67 68 74 3E 6B 5F 5F 42 61 63 6B 69 6E 67  eight>k__Backing
00160 : 46 69 65 6C 64 01 00 00 08 08 02 00 00 00 06 03  Field...........
00176 : 00 00 00 04 54 65 73 74 2A 00 00 00 FE FF FF FF  ....Test*...????
00192 : 0B  .

这似乎有道理。让我们将该字段放在末尾:

[Serializable]
public class Human
{
    public int Age {get;set;}
    public int Weight {get; set;}   
    public string Name;
}

结果是:

00096 : 55 73 65 72 51 75 65 72 79 2B 48 75 6D 61 6E 03  UserQuery+Human.
00112 : 00 00 00 04 4E 61 6D 65 14 3C 41 67 65 3E 6B 5F  ....Name.<Age>k_
00128 : 5F 42 61 63 6B 69 6E 67 46 69 65 6C 64 17 3C 57  _BackingField.<W
00144 : 65 69 67 68 74 3E 6B 5F 5F 42 61 63 6B 69 6E 67  eight>k__Backing
00160 : 46 69 65 6C 64 01 00 00 08 08 02 00 00 00 06 03  Field...........
00176 : 00 00 00 04 54 65 73 74 2A 00 00 00 FE FF FF FF  ....Test*...????
00192 : 0B  .

完全没有变化。

最后一个例子让您相信 BinaryFormatter 的输出是一个实现细节,序列化和反序列化应该留给那个 class 而不是通过其他方式尝试。

[Serializable]
public class Human
{
    public string[] Address; 
    private string _name;

    public int Weight {get; set;} // switched
    public int Age {get;set;}

    public string Name {get{return _name;} set{_name=value;}}
}

如果我们初始化 class 如下:

new Human{ Name ="Test", Age = 42, Weight = -1, Address =new []{"foo","bar"}}

hexdump 将显示:

00096 : 55 73 65 72 51 75 65 72 79 2B 48 75 6D 61 6E 04  UserQuery+Human.
00112 : 00 00 00 07 41 64 64 72 65 73 73 05 5F 6E 61 6D  ....Address._nam
00128 : 65 17 3C 57 65 69 67 68 74 3E 6B 5F 5F 42 61 63  e.<Weight>k__Bac
00144 : 6B 69 6E 67 46 69 65 6C 64 14 3C 41 67 65 3E 6B  kingField.<Age>k
00160 : 5F 5F 42 61 63 6B 69 6E 67 46 69 65 6C 64 06 01  __BackingField..
00176 : 00 00 08 08 02 00 00 00 09 03 00 00 00 06 04 00  ................
00192 : 00 00 04 54 65 73 74 FF FF FF FF 2A 00 00 00 11  ...Test????*....
00208 : 03 00 00 00 02 00 00 00 06 05 00 00 00 03 66 6F  ..............fo
00224 : 6F 06 06 00 00 00 03 62 61 72 0B  o......bar.

注意 Address 和 _name 的顺序,尽管 string[] 数组的实际值放在末尾。

所以回答你的问题:

I would like to know what is the order of the properties in the serialized byte array (according to properties order in the object class? randomly?)

这是一个实现细节,取决于字段的类型及其在 class 中的顺序。它的元数据和实际值也可能有不同的顺序。它不是随机的,也不是 class.

中的顺序

And if I can control the order of the bytes according to the props.

你似乎可以在某种程度上控制它,但这是一个非常重要的实现细节,试图影响它、预测它或依赖它是不切实际的。

请记住,您只能序列化和反序列化 class 的特定版本。没有向后兼容性。

如果您需要严格控制序列化格式,请使用开放标准,例如 XML、JSON 或 proto-buf。或者按照 Peter 的建议利用 BinaryWriter 滚动您自己的序列化程序。