C# 二進制數(shù)組與結(jié)構(gòu)體的互轉(zhuǎn)方法
本文將告訴大家在 dotnet 里面的二進制基礎(chǔ)處理知識,如何在 C# 里面將結(jié)構(gòu)體數(shù)組和二進制數(shù)組進行相互轉(zhuǎn)換的簡單方法
盡管本文屬于基礎(chǔ)入門的知識,但是在閱讀之前還請自行了解 C# 里面的結(jié)構(gòu)體內(nèi)存布局知識
本文將和大家介紹 MemoryMarshal 輔助類,通過這個輔助類用來實現(xiàn)結(jié)構(gòu)體數(shù)組和二進制數(shù)組的相互轉(zhuǎn)換
先演示如何從結(jié)構(gòu)體數(shù)組和二進制數(shù)組的相互轉(zhuǎn)換。準確來說是 Span 之間的相互轉(zhuǎn)換,而不是真的轉(zhuǎn)換為數(shù)組,只是 Span 的行為表現(xiàn)和數(shù)組十分相似
為了方便代碼演示,我定義了一個 Foo1 的結(jié)構(gòu)體,本文的全部代碼都可以在本文末尾找到下載方法
struct Foo1
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}先創(chuàng)建出一個 Foo1 結(jié)構(gòu)體數(shù)組,為了方便演示我還給 Foo1 的各個屬性分別賦值,如以下代碼
var foo1 = new Foo1()
{
A = 1,
B = 2,
C = 3,
};
var foo1Array = new Foo1[] { foo1 };拿到 Foo1 的數(shù)組之后,可以非常方便轉(zhuǎn)換為 Span 類型,只需要調(diào)用 foo1Array.AsSpan() 即可。接下來將 Foo1 數(shù)組轉(zhuǎn)化在二進制數(shù)組,準確來說是 Span<byte> 類型,代碼如下
Span<byte> foo1ByteSpan = MemoryMarshal.AsBytes(foo1Array.AsSpan());
此時編寫一個輔助方法,將 foo1ByteSpan 的內(nèi)容輸出到控制臺,方便讓大家看到這個 foo1ByteSpan 對象就確實是 Foo1 結(jié)構(gòu)體的內(nèi)存空間的二進制內(nèi)容
Log(foo1ByteSpan); // 01 00 00 00 02 00 00 00 03 00 00 00
private static void Log(Span<byte> byteSpan)
{
var stringBuilder = new StringBuilder();
foreach (var b in byteSpan)
{
stringBuilder.Append(b.ToString("X2"));
stringBuilder.Append(' ');
}
Console.WriteLine(stringBuilder.ToString());
}可以看到以上輸出的 01 02 03 就是對應(yīng) Foo1 結(jié)構(gòu)體的 A 和 B 和 C 屬性的值。本文這里沒有對 Foo1 結(jié)構(gòu)體進行固定布局等,這一點不夠嚴謹,也就是說我只能和大家保證一定出現(xiàn) Foo1 結(jié)構(gòu)體的 A 和 B 和 C 屬性的值,但是不能保證這些值出現(xiàn)的順序。如果不了解這部分的知識,還請自行查閱 dotnet 里面的結(jié)構(gòu)體的內(nèi)存布局優(yōu)化和內(nèi)存對齊
接下來開始證明本文以上拿到的 foo1ByteSpan 和 foo1Array 指向相同的一片內(nèi)存地址空間,也就是對 foo1Array 或 foo1ByteSpan 的內(nèi)存修改,都會相互影響
先修改 foo1Array 里面的內(nèi)容,比如修改一個屬性的內(nèi)容,如以下代碼
foo1Array[0].C = 5;
Log(foo1ByteSpan); // 01 00 00 00 02 00 00 00 05 00 00 00可以看到修改了 C 屬性之后,打印出的 foo1ByteSpan 也更改了
再嘗試修改 foo1ByteSpan 的內(nèi)容,看看是否也能反過來影響到 foo1Array 對象
foo1ByteSpan[0] = 6;
Console.WriteLine(foo1Array[0].A); // 6
var foo1Span = MemoryMarshal.Cast<byte, Foo1>(foo1ByteSpan);
Console.WriteLine(foo1Span[0].A); // 6通過以上代碼即可證明了 foo1ByteSpan 和 foo1Array 指向相同的一片內(nèi)存地址空間,也就是 MemoryMarshal.Cast 和 MemoryMarshal.AsBytes 不是重新申請一片內(nèi)存空間存放數(shù)組內(nèi)容,而是僅僅編寫的代碼上的魔法,內(nèi)存都是相同的一片空間。如此減少了內(nèi)存空間轉(zhuǎn)換拷貝,可以極大的提升性能,同時也兼顧了安全性
通過 MemoryMarshal.Cast 方法,不僅可以支持結(jié)構(gòu)體和 byte 之間的轉(zhuǎn)換,也可以進行結(jié)構(gòu)體之間的轉(zhuǎn)換,比如再定義一個 Foo2 類型,這個 Foo2 類型和 Foo1 類型有相同的屬性只是類型不相同而已,試試使用以下代碼進行相互轉(zhuǎn)換
var foo2Span = MemoryMarshal.Cast<Foo1, Foo2>(foo1Span);
Console.WriteLine(foo2Span[0].A); // 6
Console.WriteLine(foo2Span[0].B); // 2
Console.WriteLine(foo2Span[0].C); // 5
struct Foo2
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}可以看到通過 MemoryMarshal.Cast 是可以實現(xiàn)多個結(jié)構(gòu)體之間的直接轉(zhuǎn)換的,且沒有重新在堆上重新開辟數(shù)組空間
但是本文以上的代碼是不嚴謹?shù)?,以上代碼沒有固定 Foo1 結(jié)構(gòu)體和 Foo2 結(jié)構(gòu)體的內(nèi)存布局,以上的代碼只是用來告訴大家 MemoryMarshal.Cast 的用法,而不是推薦大家在正式的項目跟隨我這么寫。如果在正式項目里面,需要確保多個結(jié)構(gòu)體之間的內(nèi)存布局相同或者是在各個情況下的直接內(nèi)存轉(zhuǎn)換是符合預(yù)期的才能這么做
可以通過如下方式獲取本文的源代碼,先創(chuàng)建一個空文件夾,接著使用命令行 cd 命令進入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼
git init git remote add origin https://gitee.com/lindexi/lindexi_gd.git git pull origin 6bd28ceca1e9b73bfda270f9a3a3bddd7b8ebcc4
以上使用的是 gitee 的源,如果 gitee 不能訪問,請?zhí)鎿Q為 github 的源。請在命令行繼續(xù)輸入以下代碼
git remote remove origin git remote add origin https://github.com/lindexi/lindexi_gd.git git pull origin 6bd28ceca1e9b73bfda270f9a3a3bddd7b8ebcc4
獲取代碼之后,進入 HallehuwearjewhoQedelqarnalar 文件夾
到此這篇關(guān)于C# 二進制數(shù)組與結(jié)構(gòu)體的互轉(zhuǎn)的文章就介紹到這了,更多相關(guān)C# 二進制數(shù)組與結(jié)構(gòu)體互轉(zhuǎn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
WPF數(shù)據(jù)綁定時出現(xiàn)StringFormat失效的原因和解決方法
在數(shù)據(jù)綁定過程中,我們經(jīng)常會使用StringFormat對要顯示的數(shù)據(jù)進行格式化,以便獲得更為直觀的展示效果,但在某些情況下格式化操作并未生效,所以本文介紹了WPF數(shù)據(jù)綁定時出現(xiàn)StringFormat失效的原因和解決方法,需要的朋友可以參考下2024-12-12
C#面向?qū)ο髮崿F(xiàn)圖書管理系統(tǒng)
這篇文章主要為大家詳細介紹了C#面向?qū)ο髮崿F(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
使用C#實現(xiàn)在Excel中創(chuàng)建和配置數(shù)據(jù)透視表
在數(shù)據(jù)分析和業(yè)務(wù)報告場景中,數(shù)據(jù)透視表(Pivot?Table)是一種強大的數(shù)據(jù)匯總工具,本文將介紹如何使用?C#?在?Excel?工作表中創(chuàng)建和配置數(shù)據(jù)透視表,感興趣的小伙伴可以了解下2026-03-03
使用快捷鍵在Unity中快速鎖定和解鎖Inspector右上角的鎖功能
這篇文章主要為大家介紹了使用快捷鍵在Unity中快速鎖定和解鎖Inspector右上角的鎖功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

