轉載來的C# 2.0中P/Invoke支援的幾處增強

來源:互聯網
上載者:User

1、Array in stack

對於這樣的struct:typedef struct { int XY[2]; } Point2D;

要在.NET為一個非託管函數傳遞這樣一個結構體,原來得這樣定義:

struct Point2D
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
 public int[] XY;
}

  現在可以這麼寫(不過得用unsafe上下文):

unsafe struct Point2D
{
public fixed int XY[2];
}

 
不過這個功能還非常有限,不知道是出於什麼原因考慮,只允許在strcut裡面定義這樣的數組,並且只能使用bool, byte,
 short, int, long, char, sbyte, ushort, uint, ulong, float和double這樣的
primitive類型。

也可以把數組作為局部變數分配在堆棧上,只是文法不太一樣,那就是stackalloc關鍵字:int* fib = stackalloc int[100];,也要unsafe上下文。這可以提高不少效率。這是.NET 1.x就有的功能,只是似乎沒人用這個

PS. 對於只允許使用primitive類型,我認為是沒道理的,最起碼應該允許所有實值型別的棧內數組。設計者們為啥這麼考慮呢?怕堆疊溢位?據我測試.NET的堆棧空間也是1M左右,大部分情況下這麼大的棧空間都被浪費了。

2、Function pointer as a return value

在.NET 1.x做P/Invoke時,對於那些回呼函數,可以使用Delegate類型的參數作為函數指標傳入。但有些非託管函數的傳回值也是個函數指標,此時.NET 1.1變得無能為力,要調用這個函數,你得用native代碼再寫個封裝,總之很麻煩。

.NET 2.0的System.Runtime.InteropServices.Marshal類為此需求新增了兩個方法:

public static Delegate GetDelegateForFunctionPointer (
IntPtr ptr,
Type t
);

public static IntPtr GetFunctionPointerForDelegate (
Delegate d
);

3、Marshal過程支援更多的類型

這是一個很細的問題,比如這樣一個非託管struct:

typedef struct { Point2D XYZ[3]; } Point2DX3;

  對應到C#,你也許會這樣寫:

struct Point2D
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
 public int[] XY;
}

struct Point2DX3
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
 public Point2D[] XYZ;
}

  事實上這是不可行的。在.NET 1.x,結構體內嵌定長數組的類型必須是primitive類型,否則不能進行marshal過程。事實上調用Marshal.SizeOf時,會彈出異常說“無法得到大小”云云

.NET 2.0把這個問題給改了(與其說是個增強,還不如說是修正了這個bug),Marshal.SizeOf(typeof(Point2DX3))現在可以正常運行,輸出24 == 3 * 2 * sizeof(int)。

讓Marshal.SizeOf正常工作非常重要,得不到對象的大小,記憶體對齊都無法保證,marshal過程根本就不可行。

此外,正常工作的Marshal.SizeOf可以使這種“序列化”方式也總能正常工作(這在我以前的blog貼過,這裡是Generic版本):

unsafe class BinarySerializer
{
public static byte[] Struct2Bytes<T>(T obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
fixed (byte* pb = &bytes[0])
{
Marshal.StructureToPtr(obj, (IntPtr)pb, true);
}
return bytes;
}

public static T Bytes2Struct<T>(byte[] bytes)
{
fixed (byte* pb = &bytes[0])
{
return (T)Marshal.PtrToStructure((IntPtr)pb, typeof(T));
}
}
}

和.NET內建的序列化機制相比,這個方案效率要高得多。和.NET內建的序列化機制相似,這裡需要對象或結構體內部的所有成員都能使用
Marshal.SizeOf得到其大小,對應於“對象或結構體內部的所有成員都帶有[Serializable]特性或者實現了
ISerializable介面”。

PS. 這個序列化方案效率雖高,但不如.NET內建的方案可靠。.NET的編譯器可以檢查一個
類型能否支援序列化,而這個方案得由程式員判斷Marshal.SizeOf能否工作(比如Marshal.SizeOf絕對不會知道string類型實
際佔用多少記憶體,也就是說類型執行個體的大小必須是固定的才行)。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.