Platform Invocation Services (P/Invoke) 讓受控碼呼叫非受控 DLL 匯出函式。每次跨越受控/非受控邊界會產生 轉換開銷(Transition/Thunk),估計 10-40 條指令。頻繁呼叫會嚴重影響效能。
IntPtr 手動配置記憶體、Marshal.Copy 批次複製DllImport 最佳化:CallingConvention、CharSet、SetLastError 明確指定SuppressUnmanagedCodeSecurity:信任的高頻 API 可略過安全檢查(需極度謹慎)using System;
using System.Text;
class Program {
static void Main() {
const int Cycle = 10000;
long tick = Environment.TickCount;
// String 拼接:每次產生新實例
string str = null;
for (int i = 0; i < Cycle; i++) str += i.ToString();
Console.WriteLine($"String: {Environment.TickCount - tick} ms");
tick = Environment.TickCount;
// StringBuilder:內部緩衝區擴展,不產生中間物件
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Cycle; i++) sb.Append(i);
Console.WriteLine($"StringBuilder: {Environment.TickCount - tick} ms");
// String 不變性示範
string s1 = "A";
string s2 = s1; // 參考同一物件
Console.WriteLine(s1); // A
Console.WriteLine(s2); // A
s1 = "B"; // s1 指向新物件
Console.WriteLine(s1); // B
Console.WriteLine(s2); // A (未變)
Console.ReadLine();
}
}
String: 375 ms
StringBuilder: 16 ms
A
A
B
A
| 特性 | 說明 |
|---|---|
| 參考型別 | 儲存在堆積,變數存參考 |
| 不可變 | 任何操作(拼接、替換、截取)皆產生新實例 |
| 運算子重載 | ==/!= 比較內容值而非參考 |
| 驻留池 | 編譯期常量、String.Intern 會共用實例 |
new StringBuilder(estimatedLength) 減少擴容分配sb.Clear() 或 sb.Length = 0 重設,避免重新分配ToString() 多次呼叫:若需多次檢查內容,考慮 sb.ToString() 後快取StringBuilder 為首選;簡單拼接 2-3 字串用 + 或 string.Concat 即可
// 非託管簽章: void NativeFunc(char* buffer, int bufferSize)
// 錯誤:StringBuilder 當 out 參數但未預設容量
[DllImport("Native.dll")] static extern void NativeFunc(StringBuilder buf, int size);
// 正確:預先配置容量
StringBuilder sb = new StringBuilder(256);
NativeFunc(sb, sb.Capacity);
// 或指定 MarshalAs
[DllImport("Native.dll")]
static extern void NativeFunc([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder buf, int size);
CharSet.Ansi:單位元組字串(預設),對應 LPStrCharSet.Unicode:雙位元組字串,對應 LPWStrIn/Out 屬性明確指定資料流向,避免雙向封送開銷P/Invoke 與字串處理是效能敏感區域。記住:跨邊界呼叫要少、字串拼接用 StringBuilder、封送明確指定方向與編碼。