c# getresponsestream返回byte[]_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{.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ).maxstack 1sizeof !!Tret} // end of method Unsafe::SizeOfOK,這是 IL語言,我們就看自己關心的sizeof
#IL Code 說明sizeof 將提供的值類型的大小(以字節為單位)推送到計算堆棧上。)OK,UnsafeSizeOf
只有值類型的大小
不管我怎么改變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,我們實際測試下
Console.WriteLine(Marshal.SizeOf<myclass>().ToString());直接報錯了,因為不是一個非托管結構,沒法計算大小。
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.非值類型范型類,可用
[StructLayout(LayoutKind.Sequential)] 和Marshal.SizeOf(T)配合使用本文結束。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的c# getresponsestream返回byte[]_C++模版和C#范型求同存异录(一)sizeof(T)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea 不打开文件提示错误_IDEA无
- 下一篇: js在一个指定元素前添加内容_WebAR