2009-11-06 24 views
6

我有一個C#程序需要將字符緩衝區傳遞給非託管函數。我發現了兩種似乎可靠工作的方式,但我不確定應該選擇哪種方式。從C#調用非託管函數:我應該通過StringBuilder還是使用不安全的代碼?

這是非託管函數的簽名。

extern "C" __declspec(dllexport) int getNextResponse(char *buffer); 

第一個選項是將緩衝區定義爲StringBuilder,如下所示。

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse(StringBuilder buffer); 

//in main method body... 
StringBuilder sb = new StringBuilder(" ", 65536); 
int rc = getNextResponse(sb); 

這很簡單,和它的作品,我覺得我基本上明白爲什麼它的工作原理,因爲StringBuilder的有幕後的緩衝區,所以(我認爲)的互操作層僅僅是編組的StringBuilder爲char *。

另一種選擇是使用不安全的代碼。

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse(byte* buffer); 

//separate method... 
private static unsafe int runGetNextResponse(byte[] buffer) 
{ 
    fixed (byte* p = buffer) 
    { 
     int rc = getNextResponse(p); 
     return rc; 
    }    
} 

//in main method body... 
byte[] b = new byte[65536]; 
int rc = runGetNextResponse(b); 

第二種方法是更多的代碼,但它也更清楚地說明發生了什麼。

這兩種方法基本上是一樣的嗎?有沒有什麼理由選擇一個呢?

回答

8

我非常喜歡使用StringBuilder版本。

這兩者之間不會有太大的差異,而使用不安全的代碼幾乎沒有那麼幹淨。

在我看來,由於有一種方法可以使用核心庫類來解決問題,所以使用不安全的代碼而沒有明確(和需要)的好處是一個過早的優化。

+0

如果垃圾收集器在getNextResponse執行過程中重新分配沒有固定語句的StringBuilder會發生什麼? 導入函數中使用的每個指針參數都應該是固定的?或者我錯過了seomthing? – Luca 2009-12-07 09:02:58

2

儘管我無法確定權重,但我可以分享我自己的經驗。我專門使用了StringBuilder方法,並且沒有任何問題。我喜歡它的簡單代碼和避免不安全。

3

雖然使用StringBuilder是首選,但有一個警告。想象一下,例如,在你的getNextResponse方法,你的存儲指向一些靜態變量,並在另一種方法使用它:

char* globalPointer; 

int getNextResponse(char *buffer) { 
    globalPointer = buffer; 
    return 0; 
} 

void someOtherMethod() { 
    printf("%s\n", globalPointer); 
} 

現在讓我們來看看管理方面:

var sb = new StringBuilder(); 
sb.Append("Hello World"); 
int result = getNextResponse(sb); 
Console.WriteLine(result); 
someOtherMethod(); // kaboom: The GC could have already destroyed the string builder. 

不安全的方法,保證了你內存位置不會移動:

byte[] buffer = Encoding.UTF8.GetBytes("Hello World"); 
fixed (byte* p = buffer) 
{ 
    int result = getNextResponse(p); 
    Console.WriteLine(result); 
    someOtherMethod(); // works fine as the buffer address is pinned down in memory 
} 

在這種情況下,不安全的版本會更好。

0

這取決於緩衝區中的數據實際上是什麼。如果是字符數據,則使用StringBuilder方法。如果它是二進制數據,則改爲使用字節數組,但不要使用不安全的方法。儘管普遍存在的對「不安全」的誇大恐懼有點愚蠢,並且沒有理由不在必要時不使用它,在這種情況下,這是不必要的。使用:

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse([In, Out] byte[] buffer); 

//in main method body... 
byte[] buffer = new byte[65536]; 
int rc = getNextResponse(buffer); 
1

這取決於編組的成本。如果您進行了大量編組或者編組數據很大,您可能需要重新使用緩衝區,而不是每次創建/銷燬字符串生成器緩衝區。

相關問題