static void ChineseGreeting(string name) {
Console.WriteLine("早上好,", name); // 錯誤:缺少格式佔位符
}
static void EnglishGreeting(string name) {
Console.WriteLine("Good morning,", name);
}
// Main
gm.Delegate1 = ChineseGreeting;
gm.Delegate1 += EnglishGreeting;
gm.GreetPeople("zz"); // 輸出:"早上好," "Good morning," (無 "zz")
Console.WriteLine(string format, params object[] args) 需格式字串含佔位符({0}、{1}...)。原碼 "早上好," 無佔位符,name 被視為 params 陣列第一個元素但從未被格式化,故不輸出。
// 寫法 1:複合格式(推薦)
Console.WriteLine("早上好,{0}", name);
// 寫法 2:字串插值 (C# 6+)
Console.WriteLine($"早上好,{name}");
// 寫法 3:字串串接(效能稍差)
Console.WriteLine("早上好," + name);
| 運算子 | 行為 | 適用場景 |
|---|---|---|
= | 指派新委派鏈,覆蓋原有調用列表 | 單一訂閱者、重設委派 |
+= | 加入至現有調用列表尾端(多播委派) | 多訂閱者、事件註冊 |
delegate void D(string s);
D d = M1; // d 指向 M1
d += M2; // d 現在指向 M1 -> M2
d("hi"); // 依序呼叫 M1("hi"), M2("hi")
d = M3; // d 現在僅指向 M3(M1, M2 被移除)
d("hi"); // 僅呼叫 M3("hi")
因此 gm.Delegate1 = ChineseGreeting; gm.Delegate1 += EnglishGreeting; 與 gm.Delegate1 += ChineseGreeting; gm.Delegate1 += EnglishGreeting; 在Delegate1 初始為 null時行為相同(皆建立雙方法鏈)。若 Delegate1 已有訂閱者,= 會清空舊訂閱。
public class GreeteManager {
public event Action<string> Greet; // 編譯器自動生成 add/remove 與私有委派欄位
public void GreetPeople(string name) {
Greet?.Invoke(name); // 安全呼叫(C# 6+ null 條件運算子)
}
}
// 使用
gm.Greet += ChineseGreeting;
gm.Greet += EnglishGreeting;
gm.GreetPeople("zz");
event 關鍵字限制外部只能 +=/-=,不可 = 覆蓋,也不可直接 Invoke,符合發布/訂閱模式封裝性。
Console.WriteLine 格式字串缺 {0}。= 覆蓋、+= 累加;初始為 null 時外觀相同,語意不同。event + Action/Func,避免直接暴露委派欄位。