2011-05-11 26 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