Marshal類的兩個方法StructureToPtr和PtrToStructure實現序列化

我們主要是使用Marshal類裏的兩個方法:

第一個是StructureToPtr,將數據從託管對象封送到非託管內存塊。

第二個是PtrToStructure,將數據從非託管內存塊封送到新分配的指定類型的託管對象。

只要有了這兩個相互轉換的方法,我們就可以實現序列化了。

首先我們先來看下序列化

序列化:
有一個前提條件,那就是我們必須要知道需要序列化對象的大小。

第一步:我們先求出對象的大小,然後在非託管內存中給它分配相應的內存大小。

第二步:接着我們就把這個對象封送到剛分配出來的內存中,之後我們會得到一個分配出來的內存塊首地址指針。

第三步:最後我們可以通過這個首地址指針,從指針所指的位置處開始,拷貝數據到指定的byte[]數組中,拷貝的長度就是我們爲這個對象分配出來的內存大小,得到byte[]數據後,下面的事情我就不用多說了,你可以保存到數據庫或者文件中。

反序列化:
序列化的時候我們先將一個對象封送到了非託管內存塊中,然後再把內存塊中的數據讀到byte[]數組中,

現在我們反序列化

第一步:我們先求出對象的大小,然後在非託管內存中給它分配相應的內存大小。

第二步:然後把這個byte[]數據拷貝到非託管內存塊中。

第三步:最後再從內存塊中封送指定大小的數據到對象中。

有一個地方需要注意,那就是因爲引用類型的對象我們是無法求的它的實際大小的,所以這裏的對象我們只能使用非託管對象,比如struct結構體。

所以,當我們只是用來存儲數據,不涉及任何操作的對象,我們可以把它作爲一個結構體來處理,這樣我們在序列化的時候可以節省空間開銷。

因爲你如果你要是用平常的序列化方法去序列化一個類對象,他所需要的空間開銷是要大於你去序列化一個具有相同結構的struct對象。

下面是代碼: 

public static class MyConverter
{
/// <summary>
/// 由結構體轉換爲byte數組
/// </summary>
public static byte[] StructureToByte<T>(T structure)
{
int size = Marshal.SizeOf(typeof(T));
byte[] buffer = new byte[size];
IntPtr bufferIntPtr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, bufferIntPtr, true);
Marshal.Copy(bufferIntPtr, buffer, 0, size);
}
finally
{
Marshal.FreeHGlobal(bufferIntPtr);
}
return buffer;
}

/// <summary>
/// 由byte數組轉換爲結構體
/// </summary>
public static T ByteToStructure<T>(byte[] dataBuffer)
{
object structure = null;
int size = Marshal.SizeOf(typeof(T));
IntPtr allocIntPtr = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(dataBuffer, 0, allocIntPtr, size);
structure = Marshal.PtrToStructure(allocIntPtr, typeof(T));
}
finally
{
Marshal.FreeHGlobal(allocIntPtr);
}
return (T)structure;
}
}

//////////////////////////////////測試代碼///////////////////////////////////
class Program
{
static void Main(string[] args)
{
Student student1 = new Student { Name = "胡昌俊", ID = 2 };
Console.WriteLine("序列化前=> 姓名:{0} ID:{1}", student1.ID, student1.Name);

byte[] bytes = MyConverter.StructureToByte<Student>(student1);
Student sudent2 = MyConverter.ByteToStructure<Student>(bytes);

Console.WriteLine("序列化後=> 姓名:{0} ID:{1}", sudent2.ID, sudent2.Name);
Console.Read();
}
}

public struct Student
{
public int ID { get; set; }
public string Name { get; set; }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章