C#中Struct與IntPtr轉換:實用擴展方法

C#中Struct與IntPtr轉換:實用擴展方法

在 C# 編程的世界里,我們常常會遇到需要與非托管代碼交互,或者進行一些底層內存操作的場景。這時,IntPtr類型就顯得尤為重要,它可以表示一個指針或句柄,用來指向非托管內存中的數據。而結構體作為一種常用的數據結構,在與IntPtr進行數據傳遞和轉換時,往往需要一些繁瑣的操作。為了簡化這些操作,提高開發效率,我們可以通過擴展方法來封裝相關的功能。接下來,就為大家介紹兩段非常實用的 C# 擴展方法代碼,它們實現了結構體與IntPtr之間的轉換等功能。

一、代碼概覽

我們有兩個擴展方法類,分別是StructExtensionsIntPtrExtensionsStructExtensions類主要提供將結構體和結構體數組轉換為IntPtr的方法;IntPtrExtensions類則提供了將IntPtr轉換回結構體、將IntPtr指向的內存數據轉換為字節數組,以及釋放IntPtr所占用的非托管內存的方法。

1. StructExtensions 類

using System;
using System.Runtime.InteropServices;public static class StructExtensions
{/// <summary>/// struct to IntPtr/// IntPtr使用完,需釋放/// </summary>/// <typeparam name="T">struct</typeparam>/// <param name="value">struct值</param>/// <returns>IntPtr</returns>public static IntPtr ToIntPtr<T>(this T value) where T : struct{var intptr = Marshal.AllocHGlobal(Marshal.SizeOf(value));Marshal.StructureToPtr(value, intptr, true);return intptr;}/// <summary>/// struct[] to IntPtr/// IntPtr使用完,需釋放/// </summary>/// <typeparam name="T">struct</typeparam>/// <param name="value">struct[]值</param>/// <returns>IntPtr</returns>public static IntPtr ToIntPtr<T>(this T[] value) where T : struct{var intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * value.Length);var longPtr = intPtr.ToInt64();for (var i = 0; i < value.Length; i++){var rectPtr = new IntPtr(longPtr);Marshal.StructureToPtr(value[i], rectPtr, false);longPtr += Marshal.SizeOf(typeof(T));}return new IntPtr(longPtr);}
}

在這個類中,第一個ToIntPtr方法接受一個結構體類型的參數value,首先使用Marshal.AllocHGlobal方法在非托管內存中分配足夠的空間,空間大小由Marshal.SizeOf(value)確定,即結構體實例的大小。然后通過Marshal.StructureToPtr方法將結構體實例的值復制到分配的非托管內存中,并返回指向該內存的IntPtr。需要注意的是,使用完返回的IntPtr后,必須釋放其占用的內存,否則會導致內存泄漏。

第二個ToIntPtr方法則是針對結構體數組,它根據數組的長度和單個結構體的大小,在非托管內存中分配相應大小的空間,并返回指向該內存的IntPtr。不過,此方法只是分配了內存,并沒有將數組中的數據復制到內存中,如果需要復制數據,還需要進一步的操作。

2. IntPtrExtensions 類

using System;
using System.Runtime.InteropServices;public static class IntPtrExtensions
{public static T ToStructure<T>(this IntPtr value) where T : struct{return (T)Marshal.PtrToStructure(value, typeof(T));}public static byte[] ToBytes(this IntPtr value, int size){var bytes = new byte[size];Marshal.Copy(value, bytes, 0, size);return bytes;}public static void Free(ref this IntPtr value){Marshal.FreeHGlobal(value);}
}

IntPtrExtensions類中的ToStructure方法,接受一個IntPtr類型的參數value,通過Marshal.PtrToStructure方法將IntPtr指向的非托管內存中的數據轉換為指定的結構體類型,并返回轉換后的結構體實例。
ToBytes方法將IntPtr指向的內存中的數據讀取到一個字節數組中。它接受一個表示內存大小的參數size,首先創建一個指定大小的字節數組,然后使用Marshal.Copy方法將IntPtr指向的內存數據復制到字節數組中,并返回該字節數組。
Free方法用于釋放IntPtr所占用的非托管內存,通過Marshal.FreeHGlobal方法來實現內存的釋放,由于需要修改IntPtr本身,所以參數使用了ref關鍵字。

二、使用示例

下面我們通過一個簡單的示例來展示這些擴展方法的具體使用:

using System;
using System.Runtime.InteropServices;struct Point
{public int X;public int Y;
}class Program
{static void Main(){var point = new Point { X = 10, Y = 20 };// 將結構體轉換為IntPtrvar intPtr = point.ToIntPtr();// 將IntPtr轉換回結構體var newPoint = intPtr.ToStructure<Point>();Console.WriteLine($"X: {newPoint.X}, Y: {newPoint.Y}");// 釋放IntPtr占用的內存intPtr.Free();var points = { new Point { X = 1, Y = 2 }, new Point { X = 3, Y = 4 } };// 將結構體數組轉換為IntPtrvar arrayIntPtr = points.ToIntPtr();// 這里可以添加將數組數據復制到內存的操作// 釋放IntPtr占用的內存arrayIntPtr.Free();}}

在這個示例中,我們定義了一個Point結構體,然后分別演示了將結構體和結構體數組轉換為IntPtr,再將IntPtr轉換回結構體,以及釋放IntPtr所占用內存的整個過程。

三、注意事項

    1. 內存管理:正如前面多次提到的,使用Marshal.AllocHGlobal分配的非托管內存必須手動釋放,否則會造成內存泄漏。在實際應用中,要確保在合適的時機調用Free方法。
    1. 數據一致性:在將結構體數組轉換為IntPtr時,如果需要將數組數據復制到內存中,需要額外編寫代碼實現,否則IntPtr指向的內存中數據是未初始化的。
    1. 類型安全:在使用ToStructure方法時,要確保IntPtr指向的內存中的數據與目標結構體類型一致,否則可能會導致類型轉換錯誤或程序異常。

通過這些實用的擴展方法,我們可以更加便捷地在 C# 中處理結構體與IntPtr之間的數據轉換和內存操作,提高代碼的可讀性和可維護性。希望本文對你在 C# 編程中處理相關問題有所幫助,如果你在使用過程中有任何疑問或遇到其他問題,歡迎在評論區交流討論。

以上博客介紹了代碼的功能和使用要點。你若覺得內容還需補充,比如增加更多示例或詳細解釋某個部分,歡迎告訴我。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83664.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83664.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83664.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

手機歸屬地查詢接口如何用Java調用?

一、什么是手機歸屬地查詢接口&#xff1f; 是一種便捷、高效的工具&#xff0c;操作簡單&#xff0c;請求速度快。它不僅能夠提高用戶填寫地址的效率&#xff0c;還能幫助企業更好地了解客戶需求&#xff0c;制定個性化的營銷策略&#xff0c;降低風險。隨著移動互聯網的發展…

43、視圖解析-Thymeleaf初體驗

43、視圖解析-Thymeleaf初體驗 “43、視圖解析-Thymeleaf初體驗”通常是指在學習Spring Boot框架時&#xff0c;關于如何使用Thymeleaf模板引擎進行視圖解析的入門課程或章節。以下是對該主題的詳細介紹&#xff1a; #### Thymeleaf簡介 - **定義**&#xff1a;Thymeleaf是一個…

Day 40訓練

Day 40 訓練 PyTorch 圖像數據訓練與測試的規范寫法單通道圖像的規范訓練流程數據預處理與加載模型定義訓練與測試函數封裝模型訓練執行 彩色圖像的擴展應用數據預處理調整模型結構調整 關鍵要點總結 知識點回顧&#xff1a; 彩色和灰度圖片測試和訓練的規范寫法&#xff1a;封…

杰理可視化SDK--系統死機異常調試

杰理可視化SDK--系統死機異常調試 系統異常原因杰理SDK異常調試準備工作杰理SDK系統異常定位異常代碼示例1異常代碼示例2 在使用杰理可視化SDK進行軟件開發時&#xff0c;往往會遇到一些系統異常問題&#xff0c;系統異常是指芯片在運行代碼時&#xff0c;由于軟件或硬件狀態出…

圖簡記。。

模仿&#xff1a; algorithm-journey/src/class059/Code01_CreateGraph.java at main algorithmzuo/algorithm-journey Code01_CreateGraph C語言&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAXN 11 #define MAX…

Linux 常用命令與 Shell 簡介

文章目錄 **Linux 常用命令與 Shell 簡介****Shell 簡介****什么是 Shell&#xff1f;****Shell 的工作原理****常見 Shell 類型****命令行基礎****Tab 補全與通配符** **Linux 常用命令****1. 入門必備命令****1.1 尋求幫助 - man 命令****1.2 用戶間切換 - su 命令****1.3 特…

基于51單片機的超聲波智能避障小車仿真

目錄 具體實現功能 設計介紹 資料內容 全部內容 資料獲取 具體實現功能 &#xff08;1&#xff09;超聲波實時測量小車與障礙物間的距離&#xff0c;并用LCD1602顯示。 &#xff08;2&#xff09;當測得的距離超過50時&#xff0c;前進電機轉動&#xff08;模擬后輪&#…

AIGC工具平臺-GPT-SoVITS-v4-TTS音頻推理克隆

聲音克隆與語音合成的結合&#xff0c;是近年來生成式AI在多模態方向上的重要落地場景之一。隨著預訓練模型能力的增強&#xff0c;結合語音識別、音素映射與TTS合成的端到端系統成為初學者可以上手實踐的全流程方案。 圍繞 GPT-SoVITS-v4-TTS 模塊&#xff0c;介紹了其在整合…

Android7 Input(十)View 處理Input事件pipeline

概述: 本文主要描述View對InputEvent事件pipeline處理過程。 本文涉及的源碼路徑 frameworks/base/core/java/android/view/ViewRootImpl.java InputEvent事件處理 View處理input事件是調用doProcessInputEvents方法&#xff0c;如下所示: void doProcessInputEvents() {//…

Neo4j 完全指南:從入門到精通

第1章&#xff1a;Neo4j簡介與圖數據庫基礎 1.1 圖數據庫概述 傳統關系型數據庫與圖數據庫的對比圖數據庫的核心優勢圖數據庫的應用場景 1.2 Neo4j的發展歷史 Neo4j的起源與演進Neo4j的版本迭代Neo4j在圖數據庫領域的地位 1.3 圖數據庫的基本概念 節點(Node)與關系(Relat…

網心云 OEC/OECT 筆記(1) 拆機刷入Armbian固件

目錄 網心云 OEC/OECT 筆記(1) 拆機刷入Armbian固件網心云 OEC/OECT 筆記(2) 運行RKNN程序 外觀 內部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的網絡盒子, 沒有HDMI輸入輸出. 硬件上 OEC 和 OECT…

攝像機ISP處理流程

1.Bayer&#xff1a;生成raw圖&#xff0c;添加色彩數據&#xff08;RGB&#xff09;&#xff0c;一般會將G的占比設置為R和B的和&#xff0c;實例&#xff1a; 2.黑電平矯正&#xff1a;減去暗電流造成的誤差&#xff1b; 3.鏡頭矯正&#xff1a;對四周的亮度進行矯正&#x…

【后端架構師的發展路線】

后端架構師的發展路線是從基礎開發到技術領導的系統性進階過程&#xff0c;需融合技術深度、架構思維和業務洞察力。以下是基于行業實踐的職業發展路徑和關鍵能力模型&#xff1a; 一、職業發展階梯? 初級工程師&#xff08;1-3年&#xff09;? 核心能力?&#xff1a;掌…

Unity VR/MR開發-VR開發與傳統3D開發的差異

視頻講解鏈接&#xff1a;【XR馬斯維】VR/MR開發與傳統3D開發的差異【UnityVR/MR開發教程--入門】_嗶哩嗶哩_bilibili

RabbitMQ如何保證消息可靠性

RabbitMQ是一個流行的開源消息代理&#xff0c;它提供了可靠的消息傳遞機制&#xff0c;廣泛應用于分布式系統和微服務架構中。在現代應用中&#xff0c;確保消息的可靠性至關重要&#xff0c;以防止消息丟失和重復處理。本文將詳細探討RabbitMQ如何通過多種機制保證消息的可靠…

批量圖片管理軟件介紹

軟件介紹 本文介紹一款功能全面的圖片處理軟件 - FastStone Image Viewer。 軟件功能概述 FastStone Image Viewer不僅支持圖片查看&#xff0c;還具備編輯、批量重命名和批量轉換等多種實用功能。 用戶授權說明 該軟件對個人用戶完全免費&#xff0c;企業用戶只需輸入用戶…

Playwright 測試框架 - Java

??【Playwright + Java 實戰教程】從零到一掌握自動化測試利器! ?? 本文專為 Java 開發者量身打造,通過詳盡示例帶你快速掌握 Playwright 自動化測試。涵蓋基礎操作、表單交互、測試框架集成、高階功能及常見實戰技巧,適用于企業 UI 測試與 CI/CD 場景。 ??? 一、環境…

nvidia系列教程-Usb otg模式修改為host模式

目錄 前言 一、了解 USB OTG 模式與 Host 模式 二、host模式切換 總結 前言 在 NVIDIA 設備的使用過程中,有時我們需要將 USB OTG(On-The-Go)模式切換為 Host 模式,以滿足連接外部設備(如 U 盤、鼠標、鍵盤等)的需求。本文將詳細介紹如何在 NVIDIA 設備上進行這一模式…

二叉樹-104.二叉樹的最大深度-力扣(LeetCode)

一、題目解析 這里需要注意根節點的深度是1&#xff0c;也就是說計算深度的是從1開始計算的 二、算法原理 解法1&#xff1a;廣度搜索&#xff0c;使用隊列 解法2&#xff1a;深度搜索&#xff0c;使用遞歸 當計算出左子樹的深度l&#xff0c;與右子樹的深度r時&#xff0c;…

Calendar類日期設置進位問題

背景 報表需求&#xff0c;需要傳遞每組數據中最小的日期&#xff0c;后臺根據傳遞的最小日期&#xff0c;向前取參數傳遞的月份的上個月為結束時間的近五個月數據 例&#xff1a;參數傳:2025/02&#xff0c;則需返回2025/01, 2024/12, 2024/11, 2024/10, 2024/09這五個年月數據…