C#BinaryFormatter字节顺序

问题描述 投票:0回答:1

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

例如, 如果我序列化以下obj:

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

如果我将它序列化,那么字节的顺序是什么意思? (前4个字节是否代表年龄,下一个是权重?依此类推..或者二进制格式化程序设置为randomaly)

c# .net serialization deserialization binaryformatter
1个回答
4
投票

你为什么不试试呢?让我们上课

[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  .

这就是汉斯所说的错综复杂的格式。如果你斜视一下,你会认出一个程序集名称,类名,字段名(种类),如果你应用jdweng提供的魔法,你会注意到4个字节的2A 00 00 00会产生42(Age)而接下来的4个字节代表-1(重量)。

让我们添加一个公共字段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的输出是一个实现细节,序列化和反序列化应留给该类,而不是通过其他方式尝试。

[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;}}
}

如果我们按如下方式初始化该类:

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 []数组的实际值放在最后。

所以回答你的问题:

我想知道序列化字节数组中属性的顺序是什么(根据对象类中的属性顺序?随机?)

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

如果我可以根据道具控制字节的顺序。

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.