cv.cm

編碼 · 程式語言

C# 入門教學

閱讀約 9 分鐘

簡答

C# 是 Microsoft 推出的靜態型別物件導向語言,執行於 .NET 之上,.NET 是可在 Windows、macOS 與 Linux 上使用的免費跨平台執行環境。安裝 .NET SDK 後執行 dotnet new console,再執行 dotnet run 就會印出「Hello, World!」。核心概念包括類別與 record、List<T> 和 Dictionary<K, V> 等泛型集合、LINQ 查詢、async/await、模式比對與例外處理。

開啟JSON 格式化

C# 是什麼,用來做什麼

C#(讀作「C sharp」)由 Microsoft 內部以 Anders Hejlsberg 為首的團隊設計,於 2002 年首次發布。它由 Ecma 標準化(ECMA-334),並與 .NET 一同以開放方式開發。C# 用於網頁 API 與網站(ASP.NET Core)、Windows 桌面應用程式、跨平台行動與桌面應用程式(.NET MAUI)、雲端服務與遊戲:Unity 引擎就使用 C# 撰寫遊戲腳本。它的語法屬於 C 家族,因此 Java、C++ 與 JavaScript 開發者會覺得很熟悉。

安裝 .NET 並執行 Hello, world

從 dot.net 下載 .NET SDK,並用 dotnet --version 確認。建立並執行主控台專案:

dotnet new console -o HelloApp
cd HelloApp
dotnet run
# Hello, World!

範本會建立 Program.cs,它使用最上層陳述式(top-level statements),因此小程式不需要類別或 Main 方法:

Console.WriteLine("Hello, World!");

變數與基本型別

每個變數都有靜態型別。var 讓編譯器根據值推論型別。實值型別(數字、bool、struct)直接保存資料;參考型別(string、類別、陣列)則指向一個物件。

型別範例說明
intint n = 42;32 位元整數
longlong big = 10_000_000_000;64 位元整數
doubledouble x = 3.14;64 位元浮點數
decimaldecimal price = 19.99m;十進位,適合用於金額
boolbool ok = true;true 或 false
charchar c = 'A';UTF-16 程式碼單元
stringstring s = "hi";不可變的文字
var name = "Ada";
int count = 7;
double avg = count / 2.0;
Console.WriteLine($"{name} has {count} items, avg {avg}");  // Ada has 7 items, avg 3.5
Console.WriteLine(count / 2);                              // 3 (integer division)
Console.WriteLine(int.Parse("12") + 1);                    // 13
string? nickname = null;   // ? marks a nullable reference
Console.WriteLine(nickname ?? "none");                     // none

$"..." 是內插字串。新專案預設啟用可為 null 的參考型別,因此當可能為 null 的值未經檢查就被使用時,編譯器會發出警告。

流程控制與方法

int score = 72;
if (score >= 90) Console.WriteLine("A");
else if (score >= 70) Console.WriteLine("B");   // B
else Console.WriteLine("C");

for (int i = 0; i < 3; i++) Console.Write($"{Square(i)} ");  // 0 1 4
Console.WriteLine();

foreach (var fruit in new[] { "apple", "pear" }) Console.WriteLine(fruit);

string day = "SAT";
string kind = day switch
{
    "SAT" or "SUN" => "weekend",
    _ => "weekday",
};
Console.WriteLine(kind);   // weekend
Console.WriteLine(Greet("Lin"));                // Hello, Lin!

static int Square(int x) => x * x;
static string Greet(string name, string greeting = "Hello") => $"{greeting}, {name}!";

switch 運算式與 or 模式屬於 C# 的模式比對。方法可以有預設參數值、具名引數(Greet(name: "Lin")),以及使用 => 的運算式主體。

類別、屬性與 record

類別擁有欄位、屬性(帶有 get 與 set 邏輯的欄位)與方法。record 是以值來判斷相等性的型別,非常適合不可變資料。

var acc = new Account("Ann");
acc.Deposit(50);
Console.WriteLine($"{acc.Owner}: {acc.Balance}");   // Ann: 50

var p1 = new Point(3, 4);
var p2 = p1 with { Y = 5 };                         // copy with one change
Console.WriteLine(p1);                              // Point { X = 3, Y = 4 }
Console.WriteLine(p1 == new Point(3, 4));           // True

public class Account
{
    public string Owner { get; }
    public decimal Balance { get; private set; }

    public Account(string owner) => Owner = owner;

    public void Deposit(decimal amount)
    {
        if (amount <= 0) throw new ArgumentException("amount must be positive");
        Balance += amount;
    }
}

public record Point(int X, int Y);

型別宣告必須放在同一個檔案中最上層陳述式的後面。類別支援單一繼承(class Savings : Account),可實作任意數量的介面。

集合與 LINQ

System.Collections.Generic 中的泛型集合是日常使用的資料結構。LINQ(Language Integrated Query,語言整合查詢)為每個集合加上 Where、Select、OrderBy 與 GroupBy 等方法。

var nums = new List<int> { 3, 1, 2, 5 };
nums.Add(4);
nums.Sort();
Console.WriteLine(string.Join(", ", nums));      // 1, 2, 3, 4, 5

var ages = new Dictionary<string, int> { ["ann"] = 31, ["bob"] = 25 };
ages["cy"] = 40;
if (ages.TryGetValue("bob", out int bobAge)) Console.WriteLine(bobAge);  // 25

var evenSquares = nums.Where(n => n % 2 == 0).Select(n => n * n).ToList();
Console.WriteLine(string.Join(" ", evenSquares)); // 4 16

var oldest = ages.OrderByDescending(kv => kv.Value).First();
Console.WriteLine(oldest.Key);                    // cy

其他常見的集合還有存放不重複項目的 HashSet<T>、Queue<T>、Stack<T>,以及 int[] 這類固定大小的陣列。

招牌特色:async 與 await

C# 率先引入了後來被許多語言採用的 async/await 模型。async 方法會回傳 Task,並且可以 await 網路請求或讀取檔案這類耗時的操作,而不會阻塞執行緒。

using System.Net.Http;

using var http = new HttpClient();
var sizes = await Task.WhenAll(
    GetLengthAsync(http, "https://example.com"),
    GetLengthAsync(http, "https://example.org"));
Console.WriteLine($"downloaded {sizes.Sum()} characters");

static async Task<int> GetLengthAsync(HttpClient http, string url)
{
    string html = await http.GetStringAsync(url);
    return html.Length;
}

Task.WhenAll 會同時執行兩個請求並等待兩者都完成。using var 宣告會在作用域結束時釋放 HttpClient。

例外處理

錯誤即例外。請先捕捉特定型別,並用 finally 或 using 進行清理。對於常常不合法的輸入,TryParse 模式可以避免使用例外。

try
{
    int age = int.Parse("abc");
}
catch (FormatException ex)
{
    Console.WriteLine($"not a number: {ex.Message}");
}
finally
{
    Console.WriteLine("done");
}

if (!int.TryParse("41", out int parsed)) parsed = 0;
Console.WriteLine(parsed);   // 41

完整的小程式:單字頻率統計

將主控台專案中的 Program.cs 換成這段程式碼,然後執行 dotnet run -- notes.txt。

using System.Text.RegularExpressions;

if (args.Length != 1)
{
    Console.Error.WriteLine("usage: dotnet run -- FILE");
    return 1;
}

try
{
    string text = File.ReadAllText(args[0]).ToLowerInvariant();
    var top = Regex.Matches(text, "[a-z']+")
        .GroupBy(m => m.Value)
        .Select(g => (Word: g.Key, Count: g.Count()))
        .OrderByDescending(t => t.Count)
        .Take(5);

    foreach (var (word, count) in top)
        Console.WriteLine($"{count,5}  {word}");
    return 0;
}
catch (FileNotFoundException)
{
    Console.Error.WriteLine($"file not found: {args[0]}");
    return 1;
}

最上層陳述式可以讀取命令列的 args,也能回傳結束代碼。新專案透過隱含 using 會自動匯入 System.IO、System.Linq 與 System.Collections.Generic。

初學者常見錯誤

  • 用 double 處理金額;請改用 decimal 以避免二進位的捨入誤差。
  • 忽略可為 null 的警告,這些警告最後會變成執行階段的 NullReferenceException。
  • 在對同一個 list 的 foreach 中修改 List<T>,會拋出 InvalidOperationException。
  • 在長時間執行的應用程式中,為每個請求都建立新的 HttpClient。請重複使用同一個執行個體,或使用 IHttpClientFactory。
  • 忘記 LINQ 查詢是惰性執行的:除非呼叫 ToList(),否則每次列舉時查詢都會重新執行。

接下來學什麼

Microsoft Learn 提供官方的 C# 文件,包括語言導覽與互動式教學。接著可以學習用於網頁 API 的 ASP.NET Core、用於資料庫的 Entity Framework Core,或用於遊戲的 Unity,並使用 xUnit 或 NUnit 撰寫測試。Visual Studio、搭配 C# Dev Kit 的 VS Code,以及 JetBrains Rider 是常見的編輯器。

常見問題

C# 只能在 Windows 上使用嗎?

不是。現代 .NET 可在 Windows、macOS 與 Linux 上執行,C# 應用程式也能部署到 Linux 伺服器與容器。只有 WPF 與 Windows Forms 等部分桌面 UI 框架僅限 Windows。

C# 和 .NET 有什麼差別?

C# 是程式語言。.NET 則是用來編譯與執行 C# 程式碼(也包含 F# 與 Visual Basic)的執行環境與函式庫。

C# 和 Java 很像嗎?

在許多方面很像:兩者都是靜態型別、具垃圾回收、物件導向且採用 C 風格語法的語言。C# 另外加入了屬性、LINQ、async/await、實值型別的 struct 與 record 等功能。

C# 適合開發遊戲嗎?

適合。最廣泛使用的遊戲引擎之一 Unity 使用 C# 撰寫遊戲腳本,Godot 引擎也支援 C#。

全部編碼教學