日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C++模版和C#泛型求同存异录(一)sizeof(T)

發布時間:2023/12/4 C# 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++模版和C#泛型求同存异录(一)sizeof(T) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

sizeof(T)

從C++的模板代碼往C#代碼移植的時候發現了一個小問題。

在C++模板代碼中 sizeof(T)是一種有效的寫法,最終在會編譯器展開成sizeof(int),sizeof(float)或者sizeof(myclass),然后在運行時這個代碼是有效的,能夠執行的。于是我們看上去就可以計算在運行時計算T的大小,并分配內存。

但是在C#的泛型代碼中,sizeof(T)無法編譯過的,因為無法確認T是什么的情況下,T的大小是無法計算的,于是C#編譯器是不認的。

按C#提供的規范,sizeof只能在不安全的代碼中使用,操作的參數是非托管類型。

# 非托管類型

sbyte、byte、short、ushort、int、uint、long、ulong、

char、float、double、decimal 或 bool

任何枚舉類型
任何指針類型

任何用戶定義的 struct 類型,只包含非托管類型的字段,并且在 C# 7.3

及更早版本中,不是構造類型(包含至少一個類型參數的類型)

那么在C#的泛型類里面,該如何進行sizeof(T)操作?

然后我開始嘗試著在.net的開源代碼里面尋找答案

OK,一下子找到兩個Unsafe.SizeOf和Marshal.SizeOf

Unsafe.SizeOf

Unsafe.SizeOf 屬于 CompilerServices,繼續挖掘代碼,最后得到了一段IL Code

.method public hidebysig static int32 SizeOf<T>()

????????????????????????????cil managed aggressiveinlining

{
//....
.maxstack 1
sizeof !!T
ret
} // end of method Unsafe::SizeOf

OK,這是 IL語言,我們就看自己關心的sizeof

#IL Code 說明

sizeof

將提供的值類型的大小(以字節為單位)推送到計算堆棧上。

OK,UnsafeSizeOf只有值類型的大小

Unsafe.SizeOf<myclass>();

不管我怎么改變myclass的內容,結果都是8,所以,這個不能隨便用,只能用在值類型上了。

結合C#的文檔,我蠻懷疑關鍵字sizeof要么是調用了Unsafe.Sizeof函數,要么就是直接轉換成了IL Code的sizeof。但沒什么依據,我沒在.net的源代碼里找到這一點。

Marshal.SizeOf

這個屬于 System.Runtime.InteropServices,是.net 和COM互操作的時候用的。

這個函數挖掘代碼之后是到了一些cpp代碼,基本路徑是這樣的

Marshal.SizeOf->SizeOfHelper->
MarshalNative::SizeOfClass->GetNativeSize()

Marshal.SizeOf->SizeOfHelper是C#代碼

GetNativeSize()是用C++代碼實現的,兩邊怎么焊接的我就不管了,這個暫時不關心。

最后

BOOL GetNativeSize() const
{
LIMITED_METHOD_CONTRACT;
return m_cbNativeSize;
}

返回了一個m_cbNativeSize;

OK,我們實際測試下

Marshal.SizeOf<myclass>();

直接報錯了,因為不是一個非托管結構,沒法計算大小。

Type 'ConsoleApp1.Program+myclass' cannot be marshaled as

an unmanaged structure; no meaningful size

or offset can be computed.

OK,稍微調整下代碼

加一個[StructLayout(LayoutKind.Sequential)]

然后輸出結果是12,剛好是三個int的大小。

等下,還有第三種辦法:從 C# 7.3 開始,可使用 unmanaged 約束指定:類型參數為“非指針、不可為 null 的非托管類型”。從 C# 8.0 開始,僅包含非托管類型的字段的構造結構類型也是非托管類型,如以下示例所示:

public struct Coords<T>
{
public T X;
public T Y;
}


public class UnmanagedTypes
{
public static void Main()
{
DisplaySize<Coords<int>>();
DisplaySize<Coords<double>>();
}

private unsafe static void DisplaySize<T>() where T : unmanaged
{
Console.WriteLine($"{typeof(T)} is unmanaged and its size is {sizeof(T)} bytes");
}
}
// Output:
// Coords`1[System.Int32] is unmanaged and its size is 8 bytes
// Coords`1[System.Double] is unmanaged and its size is 16 bytes

那么回到我開始的問題,如果都是值類型,兩個都可以用,如果是自定義類,用Marshal.SizeOf就可以了

或者把泛型類寫成

public struct Coords<T>

????????????????where T : unmanaged

{
public T X;
public T Y;
}

即T只限于非托管類型。

結論

1.值類型泛型類,可以用

where T : unmanaged 和sizeof(T)配合使用
或者直接使用 Unsafe.Sizeof(T)

2.非值類型泛型類,可用

Marshal.SizeOf(T)

本文結束。

? ------------------------------

寫在文后:昨天發出之后發現把“泛”字打成范了,想想還是刪除了今天再發,寫一篇技術文章從選題,寫稿,編輯,檢查錯別字,修改,到發稿來來回回幾個小時。沒有一件事情是容易的。我盡量嚴肅對待這一切,讓各位關注者能有所得。謝謝。

??------------------------------

寫多不如寫精!

? ????

我是丁長老,歡迎關注我的技術公眾號。

個人微信號nine-ding,歡迎加我微信。

如需轉發文章請加微信號獲取轉發授權

總結

以上是生活随笔為你收集整理的C++模版和C#泛型求同存异录(一)sizeof(T)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。