前言
本文整理自《C# 網絡應用編程基礎練習題與答案(二)》,系統梳理 **C# 型別系統、值/參考語意、結構vs類別、陣列特性、轉換原則、裝箱拆箱、錯誤與異常、流程控制實作** 等核心基礎,並補充現代 C# 最佳實踐。
一、C# 支援的資料類型與 C++ 比較
型別分類
| 類別 | 包含類型 | 記憶體位置 |
| 值類型 | 簡單類型 (`bool, byte, sbyte, char, short, ushort, int, uint, long, ulong, float, double, decimal`)、結構 (`struct`)、列舉 (`enum`) | 棧 (Stack) / 內嵌於物件內部 |
| 參考類型 | 類別 (`class`)、介面 (`interface`)、委派 (`delegate`)、字串 (`string`)、陣列 (`array`)、`object`、`dynamic` | 堆 (Heap),棧存參考 |
C# vs C++ 關鍵差異
- 純物件導向:無全域函數/變數/常數,一切封裝於類別 (含靜態成員)。
- 型別安全:嚴格編譯期檢查,禁止隱式窄化轉換、未初始化變數使用。
- 垃圾回收 (GC):自動記憶體管理,無 `delete`/`free`,無記憶體洩漏 (非託管資源除外)。
- 簡化語法:單一 `.` 運算子 (無 `::` `->`)、無巨集、無多重繼承 (介面多實作替代)、統一型別系統 (`object` 為根)。
- 版本控制支援:組件強名稱、副檔名版本、並存執行。
二、值類型 vs 參考類型 核心差異
| 特性 | 值類型 | 參考類型 |
| 變數儲存內容 | **實際資料** | **參考 (位址)** 指向堆上物件 |
| 指派行為 (`a = b`) | **複製資料**,兩變數獨立 | **複製參考**,指向**同一物件** |
| 預設值 | 型別零值 (`0`, `false`, `null` 字元...) | `null` |
| 可為 null | 需包裝 `Nullable` (`T?`) | 天生可為 `null` |
| 傳遞給方法 | 預設 **ByVal** (複製);`ref`/`out` 可改為 ByRef | 預設 **ByRef** (傳參考副本);`ref` 可改變參考指向 |
| 繼承 | **不可繼承** (隱含 `sealed`),可實作介面 | 支援繼承 (單一類別、多介面) |
三、結構 vs 類別
| 項目 | 結構 (`struct`) | 類別 (`class`) |
| 型別分類 | 值類型 | 參考類型 |
| 記憶體 | 棧 / 內嵌 | 堆 |
| 效能 | 小型資料**極快** (無 GC 壓力、無指標間接) | 標準參考語意 |
| 適用場景 | 小型、不可變、值語意資料 (座標、顏色、日期、錢幣) | 複雜物件、可變狀態、多態、身分識別重要 |
| 建構函數 | **不可定義無參數建構函數** (CLR 自動提供零初始化) | 可定義任意建構函數 |
| 解構函數 | 不可有 | 可有 (罕用) |
| 預設值建立 | `new MyStruct()` 或 `default` → 全域零值 | `new MyClass()` → 分配堆物件;`default` → `null` |
四、陣列特性
- **參考類型** (繼承 `System.Array`),變數存參考。
- **同質性**:元素型別統一 (含 `object[]` 可裝任意型別)。
- **維度**:一維 (`int[]`)、多維 (`int[,]`)、**交錯** (`int[][]` — 陣列的陣列,每行長度可異)。
- **長度固定** (建立後不可變),需變長用 `List`。
- **邊界檢查**:存取自動檢查,越界拋 `IndexOutOfRangeException`。
五、數值型別轉換原則
- 隱式轉換:小範圍 → 大範圍 (無資料遺失) — `int → long`、`float → double`、`byte → int`。
- 顯式轉換 (Cast):大範圍 → 小範圍 (可能溢位/精度遺失) — `(int)longVal`、`(byte)intVal`。
編譯器**強制要求**寫 Cast,提醒開發者風險。
- 使用者定義轉換:`implicit` / `explicit` operator 多載。
- 輔助方法:`Convert.ToXxx()`、`Parse`/`TryParse`、`checked`/`unchecked` 區塊控制溢位行為。
六、裝箱與拆箱
int val = 42;
object obj = val; // 裝箱:在堆分配 object,複製 42 進去
int val2 = (int)obj; // 拆箱:檢查型別匹配,複製值出來
// 效能影響:頻繁裝箱產生大量暫時物件 → GC 壓力
// 避免:用泛型 List 而非 ArrayList、介面約束用 where T : struct
七、錯誤 vs 異常與處理語句
| 概念 | 說明 |
| 錯誤 | 執行期發生的**事件**,中斷正常流程,產生異常物件。 |
| 異常 | 錯誤事件建立的**物件** (繼承 `Exception`),含錯誤資訊、堆疊追蹤、時間位置。 |
| 拋出異常 | 方法發生錯誤,建立異常物件向上傳遞 (`throw`)。 |
| 處理語句 | `try-catch`、`try-catch-finally`、`throw`、`try-finally` (C# 6+ `using` 隱含)。 |
為何必須處理? 未處理異常 → 程式終止 / 執行緒崩潰 / 進程退出,健壯性歸零。
八、流程控制實作題目與標準解
題目 9:輸出 1~5 平方值 (for / while / do-while)
// for
for (int i = 1; i <= 5; i++) Console.WriteLine($"{i} 的平方 = {i*i}");
// while
int j = 1;
while (j <= 5) { Console.WriteLine($"{j} 的平方 = {j*j}"); j++; }
// do-while
int k = 1;
do { Console.WriteLine($"{k} 的平方 = {k*k}"); k++; } while (k <= 5);
題目 10:輸入 5 個大寫字母,驗證長度與字元範圍
bool ok = false;
while (!ok)
{
Console.Write("請輸入 5 個大寫字母:");
string s = Console.ReadLine();
if (s.Length != 5) { Console.WriteLine("長度必須為 5"); continue; }
ok = true;
for (int i = 0; i < 5; i++)
{
if (s[i] < 'A' || s[i] > 'Z')
{
Console.WriteLine($"第 {i+1} 字元 '{s[i]}' 非大寫字母");
ok = false; break;
}
}
}
題目 11:輸入整數 n,正數輸出 1~n,負數結束
while (true)
{
Console.Write("請輸入整數 (負數結束):");
if (!int.TryParse(Console.ReadLine(), out int n))
{ Console.WriteLine("非整數"); continue; }
if (n < 0) break;
for (int i = 1; i <= n; i++) Console.WriteLine(i);
}
題目 12:尋找 1000 以內完數 (完全數)
for (int i = 2; i <= 1000; i++)
{
int sum = 1; // 1 是所有數的因子
string expr = "1";
for (int j = 2; j <= Math.Sqrt(i); j++)
{
if (i % j == 0)
{
int pair = i / j;
if (j != pair) { sum += j + pair; expr += $"+{j}+{pair}"; }
else { sum += j; expr += $"+{j}"; }
}
}
if (sum == i) Console.WriteLine($"{i} = {expr}");
}
// 輸出: 6 = 1+2+3, 28 = 1+2+4+7+14, 496 = 1+2+4+8+16+31+62+124+248
現代 C# 補充建議
- 唯讀結構:`readonly struct Point { public int X,Y; }` 保證不可變,避免防禦性複製。
- 記錄型別:`record Person(string Name, int Age);` 自動實作值語意相等、with 運算式、不可變預設。
- 模式比對:`if (obj is int i) ...`、`switch (shape) { case Circle c: ... }` 簡化型別檢查與轉換。
- 範圍運算子:`1..5`、`^1` 簡化陣列/切片操作。
- 全域 using / 隱含 using**:.NET 6+ 專案預設簡化常用命名空間引用。
總結
C# 基礎型別系統以 **值/參考語意** 為核心分水嶺,衍生出結構/類別選型、陣列/集合選擇、傳遞機制、裝箱拆箱效能等一系列工程決策。掌握 **「值複製、參考共享」** 這一條主線,配合 **泛型、唯讀結構、記錄型別、模式比對** 等現代特性,即能寫出高效、安全、可維護的 C# 代碼。