2012-05-07 21 views
1

当我试图将一个对象转换为字节数组时,我得到一个奇怪的数组。 这是代码:对象到字节的转换

 using (MemoryStream ms = new MemoryStream()) 
     { 
      BinaryFormatter bf = new BinaryFormatter(); 
      bf.Serialize(ms, obj); 
      Console.WriteLine(ByteArrayToString(ms.ToArray())); 
     } 
//int obj = 50; 

//string ByteArrayToString(byte[] byteArr) the functionality of this method is pretty obvious 

结果是这样的:

“00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 00 04 01 00 00 00 0C 53 79 73 74 65 6D 2E 49 6E 74 33 32 01 00 00 00 07 6D 5F 76 61 6C 75 65 00 08 32 00 00 00 0B“

有人可以向我解释为什么?:)最佳结果应该只有”32 00 00 00“。

+0

这正是我期望发生的事情。您将“MemortyStream”对象而不是整数变量“obj”转换为“byte”数组。有一个'整数'字节[]'我建议你使用它。我不得不把这个问题投下来,因为看起来你没有时间试图找出答案。 –

+0

@Rhhound:你的解释没有任何意义,因为OP显然不是*序列化'MemoryStream'。请参阅['BinaryFormatter.Serialize'](http://msdn.microsoft.com/en-us/library/c5sbs8z9.aspx)。 – user7116

回答

8

由于序列化程序需要提供足够的信息来反序列化数据,它必须包含一些关于被序列化的对象的元数据。具体来说,

53 79 73 74 65 6D 2E 49 6E 74 33 32 

部分代表System.Int32

如果使用BinaryWriter及其Write(Int32)方法来代替,你会得到预期的效果:你的记忆流将包含只是从你的整数四个字节。不知道你是否在流中写入了Int32,你将无法反序列化它。

+0

+1,我认为OP在序列化的目的上有些模糊。 – user7116

+0

嗯,如果我在编译时不知道'obj'的确切类型怎么办?因为我实际上使用它来转换代表另一种类型的Object对象(仅在运行时才知道)ץ – TalBin

+1

@TalBin然后,您需要包含* some *信息来标识该对象的类型,以便将二进制数据转换回一个东西。它不一定需要是二进制格式化程序提供的数据 - 你可以创建自己的方案 - 但它需要在那里。例如,如果您知道您可以传递的所有内容都是int,字符串或double,则可以为数据添加一个额外字节,如果其余字符串为1,则将其设置为1,其余为id是一个int,如果其余的是double,则为3。细节完全取决于你,但有些信息需要在那里。 – dasblinkenlight

0

结果中的额外东西将是BinaryFormatter对象。你不只是输出int obj = 50,你也输出了包含在BinaryFormatter中的所有东西。

+2

-1,不是内存流是什么*写入*而不是什么被发送到流。 – user7116

+0

正确,misspoke,意味着键入BinaryFormatter并分心。 – tmesser

+0

为了澄清,* extra stuff *是二进制序列化的实现细节。它使'BinaryFormatter'正确地反序列化对象图。它实际上并不是“BinaryFormatter”实例本身与对象一起被序列化,而是关于对象的数量和类型的元数据。 – user7116

2

您正在合并BinaryFormatter序列化与对象的在内存格式。写入流的内容仅仅是BinaryFormatter的实现细节,不应该依赖于不使用BinaryFormatter的任何进程间通信。

如果您正在寻找内置类型的字节表示,请使用BitConverter.GetBytes(对于字符串使用相应的Encoding.GetBytes)。

1

序列化的字节数组包含数据本身和类型信息。这就是为什么你得到比你期望的更多的信息。这对后来的反序列化是必要的。

0

序列化过程使用额外的字节来存储关于类型的信息 - 这是确保序列化数据将被反序列化成相同类型的相同对象的唯一方法。 如果你确定你在做什么,并且想要避免任何额外的字节,你可以使用你自己的序列化,并使你的格式化器和序列化器非常复杂。或者,你可以使用编组:

var size = Marshal.SizeOf(your_object); 
// Both managed and unmanaged buffers required. 
var bytes = new byte[size]; 
var ptr = Marshal.AllocHGlobal(size); 
// Copy object byte-to-byte to unmanaged memory. 
Marshal.StructureToPtr(font.LogFont, ptr, false); 
// Copy data from unmanaged memory to managed buffer. 
Marshal.Copy(ptr, bytes, 0, size); 
// Release unmanaged memory. 
Marshal.FreeHGlobal(ptr); 

并以字节转换为对象:

var bytes = new byte[size]; 
var ptr = Marshal.AllocHGlobal(size); 
Marshal.Copy(bytes, 0, ptr, size); 
var your_object = (YourType)Marshal.PtrToStructure(ptr, typeof(YourType)); 
Marshal.FreeHGlobal(ptr); 

这是相当缓慢和不安全在大多数情况下使用,但它是严格对象转换为字节的最简单的方法[]没有实现序列化,没有[Serializable]属性。