C# Marshal类 两个方法StructureToPtr和PtrToStructure实现序列化和反序列化

文章详细介绍了C#中Marshal类如何通过StructureToPtr和PtrToStructure方法进行结构体与非托管内存的转换,展示了序列化和反序列化的过程,包括内存分配、对象复制和数据拷贝至byte[]数组的操作。

我们主要是使用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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值