C# 建立在 C++ 的語法與語義基礎之上,讓 C/C++ 開發者能快速享受 .NET Framework 與通用語言執行平台(CLR)帶來的生產力紅利。雖然語法相似度高,但從非受控環境邁向受控環境,意味著程式設計思維的根本轉變。本文將系統梳理記憶體管理、型別系統、元件導向特性等核心差異,並針對 C++ 開發者易犯的錯誤提供避坑指南。
IDisposable 模式釋放非受控資源。C# 的 int 實際對應 System.Int32,struct 繼承 System.ValueType,所有型別最終繼承 System.Object。這意味著:
ToString()、GetHashCode() 等方法。object 的方法時會發生裝箱,效能有額外開銷。C# 將屬性、事件、委派提升為語言一級成員,無需像 C++ 靠巨集或慣例模擬。介面取代多重繼承,避免菱形繼承難題,並在 GC 環境下更易高效實作。
// C++:struct/class 預設傳值/傳址由呼叫端決定
// C#:結構是值型別,類別是參考型別,語義由型別定義端固定
struct Point { public int X, Y; }
class Node { public int Id; }
void Modify(Point p, Node n) { p.X = 9; n.Id = 9; }
// 呼叫後:Point 未變(傳副本),Node 已改(傳參考)
對策:明確區分 struct(輕量、不可變、高頻建立)與 class(有身分識別、參考語義)。需傳值型別參考時加 ref / out。
// C++ 允許
int x; if (cond) x = 1; Console.WriteLine(x); // 可能未初始化
// C# 編譯錯誤:使用未指派的區域變數 'x'
int x;
if (cond) x = 1;
Console.WriteLine(x); // 錯誤
// 正確寫法
int x = 0; // 或 int x; if (cond) x = 1; else x = 2;
編譯器靜態流程分析確保讀取前已寫入,消除未初始化變數導致的未定義行為。
| 關鍵字 | 呼叫端需初始化 | 被呼叫端可讀/寫 | 適用場景 |
|---|---|---|---|
ref | 是 | 可讀可寫 | 雙向資料交換(如 Swap) |
out | 否 | 必須寫入 | 多返回值(如 TryParse) |
in (C# 7.2+) | 是 | 唯讀 | 大型結構唯讀傳遞,避免複製開銷 |
// C++: int arr[10]; 或 int* arr = new int[10];
// C#: 方括號跟在型別後,不可跟在變數名後
int[] arr = new int[10]; // 一維
int[,] matrix = new int[3,4]; // 多維(矩形)
int[][] jagged = new int[3][]; // 鋸齒陣列(陣列的陣列)
IEnumerable,支援陣列、集合、自訂迭代器。get/set 存取子封裝欄位,支援唯讀、唯寫、自動實作屬性(public int Age { get; set; })。obj[i] 存取。[Obsolete]、[Serializable] 等中繼資料,支援反射與 AOP。List<T> 等在執行期具現化,避免裝箱並保留型別資訊(不同於 C++ 模板在編譯期展開)。掌握這些核心差異,C++ 開發者即能在 C# 與 .NET 生態中發揮最大效能,避免將 C++ 慣用模式生搬硬套導致的效能損耗或邏輯錯誤。