由于我们两次注册回调函数 PrintOne ,因此以下代码将两次打印消息“PrintOne”。这是问题,
问题1>为什么默认情况下运算符+ =(即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();
}
}
}
答案 0 :(得分:5)
public void RegisterCall(PrintMethod methodToCall)
{
printMethods -= methodToCall;
printMethods += methodToCall;
}
这将确保在多播委托中存在时将其删除,然后添加,以确保1个实例。
如果多播委托中已存在相同处理程序的委托,则添加处理程序不会中止,因为大多数时间都不会发生重复。还有一些有效的情况,其中两次调用相同的方法是所需的(例如对象或集合上的自定义聚合)。
如果他们决定避免重复,则在添加处理程序时必须抛出异常。这在很多方面都很昂贵,无论是在运行时还是在我们必须编写的所有丑陋的try-catch
块中。
答案 1 :(得分:1)
C#中注册回调的典型设计是在您的对象上放置一个公共event
。这样,另一个类可以添加 - 同样重要的 - 删除事件处理程序。我不清楚为什么使用RegisterCall
方法而不是使用C#的内置事件注册功能。
通常,向事件添加事件处理程序的模块也将在不再需要调用时删除该处理程序。这对于任何事件处理对象来说都是必需的,该对象的预期生命周期比事件生成对象本身的持续时间短,因为委托持有对对象实例的引用并使它们保持活动状态。