最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c# unmanaged 約束的具體使用

 更新時間:2026年03月23日 10:33:06   作者:科學(xué)的發(fā)展-只不過是讀大自然寫的代碼  
本文主要介紹了c# unmanaged 約束的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧

在 C# 中,unmanaged 是一個泛型約束(generic constraint),用于限制泛型類型參數(shù)必須是非托管類型(unmanaged types)。

1. 什么是非托管類型 (Unmanaged Types)?

非托管類型是指那些在內(nèi)存中布局固定、不包含任何引用類型(如類、字符串、接口等)且不需要垃圾回收器(GC)直接管理的類型。具體來說,非托管類型包括:

  • 內(nèi)置數(shù)值類型:sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool。
  • 枚舉類型 (enum):其基礎(chǔ)類型必須是非托管類型。
  • 結(jié)構(gòu)體 (struct):該結(jié)構(gòu)體必須滿足以下條件:
    • 所有字段都是非托管類型。
    • 沒有自動實現(xiàn)的屬性(除非是 C# 10+ 的特定場景,通常指字段)。
    • 沒有析構(gòu)函數(shù)。
    • 沒有包含引用類型的字段。
  • 指針類型:如 int*, void* 等(僅在 unsafe 上下文中)。

注意:string、class、interface、delegate 以及包含這些類型的 struct 不是非托管類型。

2. 語法用法

你可以通過在泛型定義中使用 where T : unmanaged 來應(yīng)用此約束。

// 定義一個泛型方法,只接受非托管類型
public void ProcessData<T>(T data) where T : unmanaged
{
    // 可以安全地獲取指針或進行內(nèi)存拷貝
    unsafe
    {
        T* ptr = &data; 
        Console.WriteLine($"Size of {typeof(T)}: {sizeof(T)} bytes");
    }
}
// 定義一個泛型結(jié)構(gòu)
public struct UnmanagedBuffer<T> where T : unmanaged
{
    public T[] Data;
    public UnmanagedBuffer(int size)
    {
        Data = new T[size];
    }
    // 可以直接使用 sizeof(T),因為編譯器保證 T 是非托管的
    public int GetTotalSizeInBytes()
    {
        return Data.Length * sizeof(T);
    }
}

3. 主要用途和優(yōu)勢

A. 允許使用sizeof()操作符

在 C# 中,sizeof(T) 通常只能在 unsafe 代碼塊中對非托管類型使用。加上 unmanaged 約束后,你可以在泛型代碼中直接使用 sizeof(T) 而無需在每個調(diào)用點都寫 unsafe 塊(盡管方法本身可能需要標記為 unsafe 如果涉及指針操作,但在 C# 7.3+ 中,某些情況下甚至可以在非 unsafe 上下文中獲取大小,具體取決于操作)。

B. 允許使用指針 (*)

如果你需要在泛型代碼中獲取變量的地址(例如用于互操作性、高性能計算或內(nèi)存映射),必須確保類型是非托管的。

public unsafe void CopyMemory<T>(T* source, T* destination, int count) where T : unmanaged
{
    // 安全的內(nèi)存拷貝,因為編譯器知道 T 沒有引用類型,不會破壞 GC 堆
    System.Buffer.MemoryCopy(source, destination, count * sizeof(T), count * sizeof(T));
}

C. 性能優(yōu)化 (Span 和 Memory)

Span<T>Memory<T> 經(jīng)常與 unmanaged 約束一起使用,以確保數(shù)據(jù)可以連續(xù)存儲在棧上或原生內(nèi)存中,從而實現(xiàn)零分配的高性能代碼。

D. 互操作性 (Interop)

在與 C/C++ DLL 進行 P/Invoke 調(diào)用時,確保數(shù)據(jù)結(jié)構(gòu)完全匹配非托管內(nèi)存布局至關(guān)重要。unmanaged 約束可以在編譯時防止開發(fā)者意外傳入包含垃圾回收引用的復(fù)雜結(jié)構(gòu)體,從而避免內(nèi)存損壞。

4. 示例:編譯錯誤演示

public class Test
{
    // 正確:int 是非托管類型
    public void DoWorkInt() => ProcessData(10); 
    // 錯誤:string 是引用類型,不是 unmanaged
    // 編譯器報錯:The type 'string' cannot be used as type parameter 'T'... 
    // There is no boxing conversion or type parameter conversion from 'string' to 'unmanaged'.
    public void DoWorkString() => ProcessData("Hello"); 
    // 錯誤:這個結(jié)構(gòu)體包含引用類型 (string),所以它本身也不是 unmanaged
    public struct MixedStruct 
    {
        public int Id;
        public string Name; // 導(dǎo)致整個結(jié)構(gòu)體變?yōu)橥泄茴愋?
    }
    public void DoWorkMixed() => ProcessData(new MixedStruct { Id = 1, Name = "Test" });
}
public void ProcessData<T>(T data) where T : unmanaged { }

總結(jié)

where T : unmanaged 是 C# 7.3 引入的一個重要特性,它讓泛型代碼能夠安全地執(zhí)行底層內(nèi)存操作(如指針算術(shù)、sizeof、內(nèi)存塊拷貝),同時由編譯器保證類型安全性,防止將包含引用類型的對象當作純內(nèi)存塊處理。這在編寫高性能庫、游戲引擎、加密算法或硬件交互代碼時非常有用。

2.關(guān)聯(lián)知識

1.c# 非托管類型

在 C# 中,非托管類型(Unmanaged Types)是指那些內(nèi)存布局由編譯器直接控制、不包含垃圾回收(GC)引用、且可以直接與非托管代碼(如 C/C++ 庫)進行互操作的數(shù)據(jù)類型。

理解非托管類型對于使用 unsafe 代碼、指針操作、高性能計算以及與原生 DLL 交互(P/Invoke)至關(guān)重要。

1. 什么是非托管類型?

根據(jù) C# 語言規(guī)范,一個類型是“非托管”的,當且僅當:

  1. 它不是引用類型。
  2. 它不包含任何指向托管對象的引用字段。
  3. 它的內(nèi)存布局是固定的,不會因垃圾回收器的移動而改變。

簡單來說: 非托管類型就是那些可以直接用 sizeof() 獲取大小,并且可以用指針 * 指向的類型。

2. 非托管類型的分類

以下是 C# 中主要的非托管類型類別:

A. 簡單的數(shù)值類型 (Simple Numeric Types)

這些是最基本的非托管類型:

  • sbyte, byte, short, ushort, int, uint, long, ulong
  • char (注意:C# 中的 char 是 UTF-16,占2字節(jié),是非托管的)
  • float, double, decimal (注意:雖然 decimal 是值類型,但在某些舊版本的 C# 規(guī)范或特定上下文中,關(guān)于 decimal 是否完全符合“非托管”定義曾有爭議,但在現(xiàn)代 C# (C# 7.3+) 中,decimal 不是非托管類型,因為它內(nèi)部包含了對數(shù)組的引用或者其布局不適合直接的指針算術(shù),不能用于指針操作。修正:根據(jù)最新規(guī)范,decimal 實際上不是非托管類型,不能用于指針。)
    • 更正:decimal 不是非托管類型。你不能對 decimal 取地址或使用指針運算。
    • 真正的浮點非托管類型:只有 float 和 double。

B. 枚舉類型 (Enum Types)

所有枚舉類型都是非托管的,只要它們的底層類型是非托管的(默認是 int,也可以是其他整數(shù)類型)。

C. 指針類型 (Pointer Types)

任何指針類型(如 int*, void*, MyStruct*)本身也是非托管類型。這允許你創(chuàng)建指向指針的指針(int**)。

D. 用戶定義的結(jié)構(gòu)體 (User-defined Struct Types)

這是最復(fù)雜的一類。一個 struct 要成為非托管類型,必須滿足以下所有條件:

  1. 它的所有字段都必須是非托管類型。
  2. 它不能包含任何自動實現(xiàn)的屬性(除非底層字段是非托管的,但在 unsafe 上下文中通常直接訪問字段)。
  3. 它不能包含任何引用類型字段(如 string, object, class 實例, List<T> 等)。
  4. 它不能包含非固定大小的數(shù)組(除非使用 fixed 關(guān)鍵字聲明固定緩沖區(qū))。

示例:

// ? 這是一個非托管結(jié)構(gòu)體
public struct Point3D
{
    public double X;
    public double Y;
    public double Z;
}
// ? 這是一個非托管結(jié)構(gòu)體 (嵌套非托管結(jié)構(gòu)體)
public struct Particle
{
    public Point3D Position;
    public float Mass;
    public int Id;
}
// ? 這不是非托管結(jié)構(gòu)體 (包含 string 引用類型)
public struct Person
{
    public string Name; // string 是引用類型
    public int Age;
}
// ? 這不是非托管結(jié)構(gòu)體 (包含 List 引用類型)
public struct DataBuffer
{
    public System.Collections.Generic.List<int> Buffer; 
}
// ?? 特殊情況:包含固定緩沖區(qū)的結(jié)構(gòu)體
public unsafe struct FixedBufferExample
{
    public fixed byte Data[10]; // 需要 unsafe 上下文,但這使結(jié)構(gòu)體保持非托管
}

3. 如何驗證和使用非托管類型

使用sizeof運算符

只有非托管類型才能使用 sizeof 運算符(通常在 unsafe 塊中,但自 C# 7.3 起,對于純非托管類型可以在安全上下文中使用)。

Console.WriteLine(sizeof(int));      // 輸出: 4
Console.WriteLine(sizeof(double));   // 輸出: 8
Console.WriteLine(sizeof(Point3D));  // 輸出: 24 (3 * 8)
// 下面這行會編譯錯誤,因為 Person 不是非托管類型
// Console.WriteLine(sizeof(Person)); 

使用指針

只有在 unsafe 上下文中,你才能創(chuàng)建指向非托管類型的指針。

unsafe
{
    Point3D p = new Point3D { X = 1.0, Y = 2.0, Z = 3.0 };
    Point3D* ptr = &p; // 合法,因為 Point3D 是非托管類型
    // 修改值
    ptr->X = 10.0;
    // Person person = new Person();
    // Person* pPtr = &person; // 編譯錯誤:無法獲取非非托管類型的地址
}

泛型約束unmanaged

C# 7.3 引入了 unmanaged 約束,允許你限制泛型參數(shù)只能是非托管類型。這對于編寫高性能、可互操作的通用庫非常有用。

// T 必須是非托管類型
public void ProcessData<T>(T[] data) where T : unmanaged
{
    unsafe
    {
        fixed (T* ptr = data)
        {
            // 可以直接對內(nèi)存進行操作,例如傳遞給 C API
            NativeMethod(ptr, data.Length);
        }
    }
}
private static void NativeMethod(void* ptr, int length) 
{
    // 模擬調(diào)用非托管代碼
}

4. 常見誤區(qū)

  1. decimal 不是非托管類型:盡管它是值類型且主要用于數(shù)值計算,但由于其內(nèi)部實現(xiàn)復(fù)雜性(通常是 96 位整數(shù)加縮放因子,可能涉及內(nèi)部數(shù)組或不符合簡單的二進制布局規(guī)則以支持指針算術(shù)),它不能用于指針操作,也不滿足 unmanaged 約束。
  2. bool 是非托管類型:是的,bool 在 C# 中是非托管類型(通常映射為 1 字節(jié)),可以用于指針。但在與 C/C++ 互操作時要注意,C 中的 bool (stdbool.h) 通常也是 1 字節(jié),但某些舊的 C 代碼可能用 int 表示布爾值,這時需要使用 [MarshalAs] 調(diào)整。
  3. 包含引用的結(jié)構(gòu)體:只要結(jié)構(gòu)體中有一個字段是類(class)、字符串(string)、接口(interface)或委托(delegate),整個結(jié)構(gòu)體就變成托管類型,不能再作為非托管類型使用。

5. 為什么需要非托管類型?

  • 互操作性 (Interop):調(diào)用 C/C++ DLL (Win32 API, OpenGL, CUDA 等) 時,數(shù)據(jù)結(jié)構(gòu)必須內(nèi)存布局一致。
  • 性能:避免 GC 壓力,直接在棧上分配大塊數(shù)據(jù),或使用指針進行高速內(nèi)存拷貝/處理。
  • 序列化:可以將非托管類型的內(nèi)存塊直接寫入文件或網(wǎng)絡(luò)流,而不需要復(fù)雜的序列化邏輯(即“二進制序列化”)。
  • 硬件訪問:在某些底層系統(tǒng)編程場景中,需要精確控制內(nèi)存布局。

總結(jié)表

類型類別是否非托管備注
int, double, char 等基元數(shù)值? 是基礎(chǔ)構(gòu)建塊
decimal? 否不能用于指針
enum? 是底層必須是整數(shù)
struct (全字段非托管)? 是遞歸檢查所有字段
struct (含 string/class)? 否變?yōu)橥泄茴愋?/td>
pointer (int*)? 是僅在 unsafe 上下文可用
Tuple<T1, T2>? 否ValueTuple 如果泛型參數(shù)是非托管的,則 ValueTuple 也是非托管的 (C# 7.3+)

如果你需要處理具體的互操作場景或遇到特定的編譯錯誤,可以提供更多細節(jié),我可以給出針對性的代碼示例。

2.unsafe 代碼塊

在編程中,unsafe 代碼塊(Unsafe Code Block)通常指的是在默認情況下由編譯器進行內(nèi)存安全檢查的語言中,顯式聲明的一段允許進行不安全操作的代碼區(qū)域。

這個概念最常見于 C#Rust 語言中,但兩者的設(shè)計哲學(xué)和使用場景有所不同。

1. C# 中的unsafe代碼塊

在 C# 中,代碼默認是“安全”的(托管代碼),運行時(CLR)負責內(nèi)存管理、垃圾回收和邊界檢查。unsafe 關(guān)鍵字允許開發(fā)者暫時繞過這些安全檢查,直接操作內(nèi)存指針。

主要用途:

  • 指針操作:直接使用 *& 操作符處理內(nèi)存地址。
  • 高性能計算:在極度追求性能且需要手動管理內(nèi)存布局的場景(如圖像處理、游戲引擎底層)。
  • 互操作性 (Interop):調(diào)用非托管 DLL(如 C/C++ 編寫的庫)時,需要傳遞指針或處理復(fù)雜結(jié)構(gòu)體。
  • 棧分配:使用 stackalloc 在棧上快速分配內(nèi)存,避免堆分配開銷。

語法示例:

// 編譯時需要開啟 "允許不安全代碼" 選項
public unsafe void ModifyValue()
{
    int value = 10;
    int* ptr = &value; // 獲取變量地址
    *ptr = 20; // 通過指針修改值
    Console.WriteLine(value); // 輸出 20
}
// 也可以在方法級別標記
public unsafe static void ProcessBuffer(byte* buffer, int length)
{
    for (int i = 0; i < length; i++)
    {
        buffer[i] = 0; // 直接操作內(nèi)存
    }
}

風險與限制:

  • 類型安全喪失:編譯器不再保證類型匹配,可能導(dǎo)致內(nèi)存破壞。
  • 內(nèi)存泄漏/越界:沒有垃圾回收和邊界檢查,訪問非法地址會導(dǎo)致程序崩潰(Access Violation)。
  • 驗證失敗:包含 unsafe 的程序集無法通過某些嚴格的安全策略驗證(如在某些沙箱環(huán)境中)。
  • 配置要求:必須在項目文件 (.csproj) 或編譯器設(shè)置中顯式啟用 <AllowUnsafeBlocks>true</AllowUnsafeBlocks>。

2. Rust 中的unsafe代碼塊

Rust 的核心賣點是“內(nèi)存安全且無垃圾回收”。它通過所有權(quán)(Ownership)和借用檢查器(Borrow Checker)在編譯期杜絕數(shù)據(jù)競爭和懸垂指針。然而,有些底層操作是檢查器無法理解的,這時就需要 unsafe。

重要概念:在 Rust 中,unsafe 并不意味著“這段代碼是危險的”或者“關(guān)閉了所有檢查”。它的意思是:“開發(fā)者向編譯器保證,這段代碼雖然看起來違反了規(guī)則,但我人工驗證過它是安全的。”

只能在unsafe塊中執(zhí)行的操作(5大特權(quán)):

  1. 解引用裸指針 (*const T, *mut T)。
  2. 調(diào)用不安全的函數(shù)或方法 (標記為 unsafe fn)。
  3. 訪問或修改可變靜態(tài)變量 (static mut)。
  4. 實現(xiàn)不安全的 trait (unsafe impl)。
  5. 訪問聯(lián)合體的字段 (union)。

語法示例:

fn main() {
    let mut num = 5;
    // 創(chuàng)建裸指針
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;
    // 只有在 unsafe 塊中才能解引用裸指針
    unsafe {
        println!("r1 is: {}", *r1);
        *r2 = 10; // 修改值
        println!("num is now: {}", num);
    }
}
// 定義一個不安全函數(shù)
unsafe fn dangerous_function() {
    // 做一些編譯器無法驗證安全性的事
}
fn run_dangerous() {
    // 調(diào)用不安全函數(shù)也必須包在 unsafe 塊中
    unsafe {
        dangerous_function();
    }
}

最佳實踐:

  • 最小化原則:盡可能將 unsafe 代碼限制在最小的作用域內(nèi)。
  • 封裝:通常的做法是編寫一個內(nèi)部的 unsafe 實現(xiàn),然后提供一個外部的、安全的(safe)API 供用戶調(diào)用。如果外部 API 能保證無論怎么調(diào)用都不會導(dǎo)致未定義行為(UB),那么這個 API 就是安全的。
  • 文檔證明:在使用 unsafe 時,必須用注釋清楚地說明為什么這段代碼是安全的(即滿足了哪些不變量)。

總結(jié)對比

特性C# unsafeRust unsafe
核心目的突破托管環(huán)境限制,操作指針,提升性能或兼容舊代碼。告訴編譯器“我人工保證了安全”,以執(zhí)行檢查器無法驗證的底層操作。
安全性責任完全由開發(fā)者承擔,出錯容易導(dǎo)致崩潰或安全漏洞。開發(fā)者需保證邏輯正確,若違反規(guī)則會導(dǎo)致未定義行為 (UB),后果嚴重。
常見場景P/Invoke, 圖像像素處理, 模擬結(jié)構(gòu)體內(nèi)存布局。編寫操作系統(tǒng)內(nèi)核、驅(qū)動程序、高性能數(shù)據(jù)結(jié)構(gòu) (如 Vec, Box 的底層實現(xiàn))。
編譯器態(tài)度“既然你開了這個選項,我就不管你了。”“我不信任這段代碼能自動通過檢查,除非你顯式承諾它是安全的。”

如果你是在特定的語言或框架背景下遇到這個問題,請?zhí)峁└嗉毠?jié),我可以給出更針對性的解答。

到此這篇關(guān)于c# unmanaged 約束的具體使用的文章就介紹到這了,更多相關(guān)c# unmanaged 約束內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#使用Cancellation取消異步任務(wù)的全過程

    C#使用Cancellation取消異步任務(wù)的全過程

    在開發(fā)應(yīng)用程序時,我們經(jīng)常會遇到一些需要長時間運行的操作,比如:從網(wǎng)絡(luò)下載大文件、處理大量數(shù)據(jù)、執(zhí)行復(fù)雜的計算任務(wù)等,這些操作可能需要幾秒、幾分鐘甚至更長時間才能完成,為了安全地取消操作,.NET提供了CancellationToken機制,本文給大家詳細介紹一下
    2026-01-01
  • C#調(diào)用sql2000存儲過程方法小結(jié)

    C#調(diào)用sql2000存儲過程方法小結(jié)

    這篇文章主要介紹了C#調(diào)用sql2000存儲過程的方法,以實例形式分別對調(diào)用帶輸入?yún)?shù)及輸出參數(shù)的存儲過程進行了詳細分析,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • C#?RichTextBox制作文本編輯器

    C#?RichTextBox制作文本編輯器

    這篇文章主要為大家詳細介紹了C#?RichTextBox制作文本編輯器的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 適用于WebForm Mvc的Pager分頁組件C#實現(xiàn)

    適用于WebForm Mvc的Pager分頁組件C#實現(xiàn)

    這篇文章主要為大家分享了適用于WebForm Mvc的Pager分頁組件,由C#實現(xiàn),感興趣的小伙伴們可以參考一下
    2016-04-04
  • WPF實現(xiàn)能自由改變形狀的四邊形和六邊形

    WPF實現(xiàn)能自由改變形狀的四邊形和六邊形

    這篇文章主要為大家詳細介紹了WPF如何實現(xiàn)能自由改變形狀的四邊形和六邊形,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習一下
    2023-03-03
  • 快速學(xué)習c# 枚舉

    快速學(xué)習c# 枚舉

    這篇文章主要介紹了c# 枚舉的相關(guān)知識,文中講解非常細致,示例代碼幫助大家學(xué)習,感興趣的朋友可以了解下
    2020-06-06
  • C# Request.Form用法案例詳解

    C# Request.Form用法案例詳解

    這篇文章主要介紹了C# Request.Form用法案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C#滑動驗證碼拼圖驗證功能實現(xiàn)(SlideCaptcha)

    C#滑動驗證碼拼圖驗證功能實現(xiàn)(SlideCaptcha)

    目前網(wǎng)站上的驗證碼機制可謂是五花八門,有簡單的數(shù)字驗證,有摻雜了字母和文字的混淆驗證,還有通過滑塊進行的拼圖驗證,下面這篇文章主要給大家介紹了關(guān)于C#滑動驗證碼拼圖驗證功能的實現(xiàn)方法,需要的朋友可以參考下
    2022-04-04
  • 基于C#實現(xiàn)進程回收管理工具

    基于C#實現(xiàn)進程回收管理工具

    這篇文章主要為大家詳細介紹了入戶基于C#實現(xiàn)一個進程回收管理工具,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習一下
    2024-04-04
  • C#代碼實現(xiàn)復(fù)制PDF頁面

    C#代碼實現(xiàn)復(fù)制PDF頁面

    在 PDF 處理任務(wù)中,頁面復(fù)制是一項常見需求,本文將介紹如何通過 C# 代碼,利用該庫實現(xiàn)同文檔復(fù)制、跨文檔復(fù)制以及多頁面批量復(fù)制,有需要的小伙伴可以參考下
    2026-05-05

最新評論

兰西县| 青神县| 德格县| 海晏县| 仪陇县| 泰宁县| 五华县| 吴旗县| 珠海市| 平度市| 灵宝市| 襄垣县| 郸城县| 枞阳县| 武清区| 都兰县| 大同市| 缙云县| 台北县| 丰宁| 北票市| 苏尼特左旗| 依安县| 青神县| 洛南县| 香河县| 凉城县| 大英县| 两当县| 辽阳县| 洛阳市| 富川| 磐安县| 南开区| 偃师市| 常德市| 马鞍山市| 武乡县| 元朗区| 揭阳市| 河间市|