C# 二进制格式化程序字节 orde



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

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

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

如果我要序列化它,字节的顺序是什么意思?(前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(年龄)和接下来的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"}}

十六进制转储将显示以下内容:

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.

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

所以回答你的问题:

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

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

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

看起来你可以在某种程度上控制它,但这是一个如此多的实现细节,试图影响它、预测它或依赖它是不切实际的。

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

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

最新更新