我们主要是使用Marshal类里的两个方法:
第一个是StructureToPtr,将数据从托管对象封送到非托管内存块。
第二个是PtrToStructure,将数据从非托管内存块封送到新分配的指定类型的托管对象
只要有了这两个相互转换的方法,我们就可以实现序列化了。
首先我们先来看下序列化
序列化:
有一个前提条件,那就是我们必须要知道需要序列化对象的大小。
第一步:我们先求出对象的大小,然后在非托管内存中给它分配相应的内存大小。
第二步:接着我们就把这个对象封送到刚分配出来的内存中,之后我们会得到一个分配出来的内存块首地址指针。
第三步:最后我们可以通过这个首地址指针,从指针所指的位置处开始,拷贝数据到指定的byte[]数组中,拷贝的长度就是我们为这个对象分配出来的内存大小,得到byte[]数据后,下面的事情我就不用多说了,你可以保存到数据库或者文件中。
反序列化:
序列化的时候我们先将一个对象封送到了非托管内存块中,然后再把内存块中的数据读到byte[]数组中,
现在我们反序列化
第一步:我们先求出对象的大小,然后在非托管内存中给它分配相应的内存大小。
第二步:然后把这个byte[]数据拷贝到非托管内存块中。
第三步:最后再从内存块中封送指定大小的数据到对象中。
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;
}
}
Marshal 这个类:提供用于分配非托管内存、复制非托管内存块和将托管类型转换为非托管类型的方法集合,以及与非托管代码交互时使用的其他杂项方法。
Marshal是一个方法集合,主要应用在C#和非托管代码交互时,主要有如下方法:
- 分配非托管内存
- 复制非托管内存块
- 将托管类型转换为非托管类型
- 其他方法(与非托管代码交互时)
1)数组(Int64类型)写到非托管内存并读回到托管内存
using System;
using System.Runtime.InteropServices;
class Example
{
static void Main()
{
//【01】Test1_数组写到非托管内存并读回到托管内存
// Create a managed array.
Int64[] managedArray = { 1, 2, 3, 4 };
// Initialize unmanaged memory to hold the array.
int size = Marshal.SizeOf(managedArray[0]) * managedArray.Length;
IntPtr pnt = Marshal.AllocHGlobal(size);
try
{
// Copy the array to unmanaged memory.
Marshal.Copy(managedArray, 0, pnt, managedArray.Length);
// Copy the unmanaged array back to another managed array.
Int64[] managedArray2 = new Int64[managedArray.Length];
Marshal.Copy(pnt, managedArray2, 0, managedArray.Length);
Console.WriteLine("The array was copied to unmanaged memory and back.");
Console.WriteLine("————————————————");
Console.WriteLine("The array of unmanaged memory:");
//【重点】因为一个Int64占用8个字节,所以下边的偏移量为i*8
for (int i = 0; i < managedArray.Length; i++)
{
Console.Write(Marshal.ReadInt64(pnt, i * 8) + " ");
}
Console.Write("\r\n");
Console.WriteLine("————————————————");
Console.WriteLine("The back array of unmanaged memory:");
for (int i = 0; i < managedArray2.Length; i++)
{
Console.Write(managedArray2[i] + " ");
}
Console.Write("\r\n");
Console.ReadLine();
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
}
}
}

2.数组(double类型)写到非托管内存并读回到托管内存
using System;
using System.Runtime.InteropServices;
class Example
{
static void Main()
{
//【02】Test2_数组写到非托管内存并读回到托管内存
//Create a managed array.
double[] managedArray = { 0.1, 0.2, 0.3, 0.4 };
// Initialize unmanaged memory to hold the array.
int size = Marshal.SizeOf(managedArray[0]) * managedArray.Length;
IntPtr pnt = Marshal.AllocHGlobal(size);
try
{
// Copy the array to unmanaged memory.
Marshal.Copy(managedArray, 0, pnt, managedArray.Length);
// Copy the unmanaged array back to another managed array.
double[] managedArray2 = new double[managedArray.Length];
Marshal.Copy(pnt, managedArray2, 0, managedArray.Length);
Console.WriteLine("The array was copied to unmanaged memory and back.");
Console.WriteLine("————————————————");
Console.WriteLine("The array of unmanaged memory:");
//【重点】偏移量为i * Marshal.SizeOf(managedArray[0])
for (int i = 0; i < managedArray.Length; i++)
{
//How to read double???这段代码没有实现想要的效果!
Console.Write(Marshal.ReadInt64(pnt, i * Marshal.SizeOf(managedArray[0])) + " ");
}
Console.Write("\r\n");
Console.WriteLine("————————————————");
Console.WriteLine("The back array of unmanaged memory:");
for (int i = 0; i < managedArray2.Length; i++)
{
Console.Write(managedArray2[i] + " ");
}
Console.Write("\r\n");
Console.ReadLine();
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
}
}
}

3)WriteIntPtr()+ReadIntPtr()
主要过程:通过IntPtr分配非托管内存—>写内容到非托管内存中—>从非托管内存中读取内容
Marshal.AllocHGlobal—>Marshal.WriteIntPtr()—>Marshal.ReadIntPtr()
using System;
using System.Runtime.InteropServices;
class Example
{
static void Main()
{
//【03】Test3_WriteIntPtr()+ReadIntPtr()
ReadWriteIntPtr();
Console.ReadLine();
}
static void ReadWriteIntPtr()
{
// Allocate unmanaged memory.
int elementSize = Marshal.SizeOf(typeof(IntPtr));
IntPtr unmanagedArray = Marshal.AllocHGlobal(10 * elementSize);
// Set the 10 elements of the C-style unmanagedArray
for (int i = 0; i < 10; i++)
{
Marshal.WriteIntPtr(unmanagedArray, i * elementSize, (IntPtr)(i + 1));
}
Console.WriteLine("Unmanaged memory written.");
Console.WriteLine("Reading unmanaged memory:");
// Print the 10 elements of the C-style unmanagedArray
for (int i = 0; i < 10; i++)
{
Console.WriteLine(Marshal.ReadIntPtr(unmanagedArray, i * elementSize));
}
Marshal.FreeHGlobal(unmanagedArray);
Console.WriteLine("Done. Press Enter to continue.");
Console.ReadLine();
}
}
4.Fields:SystemDefaultCharSize和SystemMaxDBCSCharSize
using System;
using System.Text;
using System.Runtime.InteropServices;
public struct Point
{
public Int32 x, y;
}
public sealed class App
{
static void Main()
{
// Demonstrate the use of public static fields of the Marshal class.
Console.WriteLine("SystemDefaultCharSize={0}, SystemMaxDBCSCharSize={1}",
Marshal.SystemDefaultCharSize, Marshal.SystemMaxDBCSCharSize);
// Demonstrate the use of the SizeOf method of the Marshal class.
Console.WriteLine("Number of bytes needed by a Point object: {0}",
Marshal.SizeOf(typeof(Point)));
Point p = new Point();
Console.WriteLine("Number of bytes needed by a Point object: {0}",
Marshal.SizeOf(p));
// Demonstrate how to call GlobalAlloc and
// GlobalFree using the Marshal class.
IntPtr hglobal = Marshal.AllocHGlobal(100);
Marshal.FreeHGlobal(hglobal);
Console.ReadLine();
}
}
文章详细介绍了C#中Marshal类如何通过StructureToPtr和PtrToStructure方法进行结构体与非托管内存的转换,展示了序列化和反序列化的过程,包括内存分配、对象复制和数据拷贝至byte[]数组的操作。
3423

被折叠的 条评论
为什么被折叠?



