首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# 委派與事件:為何輸出缺少參數?= 與 += 差異解析

     編輯:程式設計綜合問答

程式碼重現

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,符合發布/訂閱模式封裝性。

總結

  1. 輸出缺少參數:Console.WriteLine 格式字串缺 {0}。
  2. = 覆蓋、+= 累加;初始為 null 時外觀相同,語意不同。
  3. 實務上優先使用 event + Action/Func,避免直接暴露委派欄位。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved