2011-05-11 25 views
4

由於我們註冊回調函數PrintOne兩次,以下代碼將兩次打印消息「PrintOne」。這裏有問題,C# - 如何處理重複的multicastdelegate?

問題1>爲什麼默認情況下operator + =(即Combine)不檢查重複的方法處理程序?

問題2>如何避免方法RegisterCall中的這種重複調用?我嘗試在MulticastDelegate/Delegate中找到一些方法,告訴我調用列表中已經有一個方法。但我沒有找到它。 http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx

謝謝

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace app3 
{ 
    class Car 
    { 
     public delegate void PrintMethod(string msg); 

     public string Name { get; set; } 

     private PrintMethod printMethods; 

     public Car() { } 
     public Car(string name) { Name = name; } 

     public void PrintCar() 
     { 
      if (printMethods != null) 
      { 
       printMethods(this.ToString()); 
      } 
      else 
      { 
       Console.WriteLine("No Method will be called"); 
      } 
     } 
     public override string ToString() 
     { 
      return string.Format("Car Name is {0}: ", Name); 
     } 

     public static void PrintOne(string msg) 
     { 
      Console.WriteLine("PrintOne"); 
     } 

     public static void PrintTwo(string msg) 
     { 
      Console.WriteLine("PrintTwo"); 
     } 

     public void RegisterCall(PrintMethod methodToCall) 
     { 
      printMethods += methodToCall; 
     } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Car mycar = new Car { Name = "BMW" }; 
      mycar.RegisterCall(new Car.PrintMethod(Car.PrintOne)); // **will print for the first time** 
      mycar.RegisterCall(new Car.PrintMethod(Car.PrintOne)); // **will print for the second time** 
      mycar.PrintCar(); 

      Console.ReadLine(); 
     } 
    } 
} 

回答

5
public void RegisterCall(PrintMethod methodToCall) 
{ 
    printMethods -= methodToCall; 
    printMethods += methodToCall; 
} 

這將確保它如果出現在多播委託刪除,然後添加,以保證1個實例。

如果同一處理程序的委託已存在於多播委託中,則添加處理程序不會中止,因爲大部分時間重複都不會發生。還有兩種調用同一方法的有效情況是需要的(例如對象或集合上的自定義聚合)。

如果他們已經決定避免重複,他們將不得不在添加處理程序時拋出異常。這在很多方面都很昂貴,無論是在運行時發生,還是在我們必須編寫的所有醜陋的try-catch塊中。

1

C#中註冊回調的典型設計是在您的對象上放置一個公共event。這樣,另一個類可以添加並且 - 同樣重要 - 刪除事件處理程序。我不清楚爲什麼你使用RegisterCall方法,而不是使用C#的內置事件註冊功能。

通常情況下,向事件添加事件處理程序的模塊也會在不再需要該調用時刪除該處理程序。這對於任何事件處理對象都是必需的,因爲委託持有對對象實例的引用並保持活動狀態,所以它的持續時間比事件生成對象本身的持續時間更短。

+1

我很快就會到達那裏。剛開始學習C#。 – q0987 2011-05-11 20:51:42