C# 委托与事件

委托的定义(What)

MSDNMicrosoft

A delegate declaration defines a reference type that can be used to encapsulate a method with a specific signature. A delegate instance encapsulates a static or an instance method.Delegates are roughly similar to function pointers in C++; however,delegates are type-safe and secure.

CodeProject

C# delegate is a callback function. It is smarter then “standard” callback because it allows defining a strict list of parameters which are passed from class-server to class-client.

C#编程指南

委托是一种引用方法的类型。 一旦为委托分配了方法,委 托将与该方法具有完全相同 的行为。委托方法的使用可 以像其他任何方法一样,具 有参数和返回值

委托与C++函数指针区别

一个delegate object 一次可以搭载多个方法,而不是一次一个。当我 们唤起一个搭载了多个方法的delegate,所有方法以其“被搭载到 delegate object 的顺序”被依次唤起 Stanley B. Lippman 一个delegate object 所搭载的方法并不需要属于同一个类。

一个 delegate object 所搭载的所有方法必须具有相同的原型和形式。然 而,这些方法可以即有static 也有non- static,可以由一个或多个不同 类的成员组成。

一个delegate type 的声明在本质上是创建了一个新的subtype instance,该subtype 派生自.NET library framework 的abstract base classes Delegate 或MulticastDelegate,它们提供一组public methods 用以询访delegate object 或其搭载的方法。

对委托的个人理解

委托是函数的封装,它代表一“类”函数。它们都符合一定的签名:拥有相同的参数列表、返回值类型。同时,委托也可以看成是对函数的抽象,是函数的“类”。此时,委托的实例将代表一个具体的函数。

为什么要使用委托?

¨ 更加灵活的方法调用

¨ 用于异步回调

¨ 多线程编程中使用委托来指定启动一个线程时调用的方法

¨ C# 中的事件模型。用它们指明处理给定事件的方法

如何委托

<modifiers> delegate <return_type> <delegate_name> ( argument_list )

public delegate void Del(string message);

public void DelegateMethod(string message) //Class DelClass

{

System.Console.WriteLine(message);

}

Del handler = new Del (obj.DelegateMethod);

handler("Hello World");

先声明委托,再实例化并指明所代具体方法

委托应用——异步回调

异步回调:由于实例化委托是一个对象,所以可以将其作为参数进行传递,也可以将其赋值给属性。这样,方法便可以将一个委托作为参数来接受,并且以后可以调用该委托。这称为异步回调,是在较长的进程完成后用来通知调用方的常用方法。以这种方式使用委托时,使用委托的代码无需了解有关所用方法的实现方面的任何信息。

public void MethodWithCallback(int param1, int param2, Del callback

{

callback("The number is: " + (param1 + param2).ToString());

}

MethodWithCallback(1, 2, handler);

回调的另一个常见用法是定义自定义的比较方法并将该委托传递给排序方法。

委托实现回调类似于接口所实现的封装?

何时委托?何时接口?

在以下情况中使用委托

¨ 当使用事件设计模式时。

¨ 当封装静态方法可取时。

¨ 当调用方不需要访问实现该方法的对象中的其他属性、

¨ 方法或接口时。

¨ 需要方便的组合。

¨ 当类可能需要该方法的多个实现时。

在以下情况中使用接口

¨ 当存在一组可能被调用的相关方法时。

¨ 当类只需要方法的单个实现时。

¨ 当使用接口的类想要将该接口强制转换为其他接口或类类型时。

多播委托

多播委托——引用多个方法的委托,它连续调用每个方法。委托必须是同类型的,返回类型必须是void,不能带输出参数(可以带引用参数)。

多播委托应用于事件模型中。

public class DelClass

{

public void Method1(string message)

{

}

public void Method2(string message)

{

}

}

DelClass obj = new DelClass();

Del d1 = obj.Method1;

Del d2 = obj.Method2;

Del d3 = obj.DelegateMethod;

Del allMethodsDelegate = d1 + d2;

allMethodsDelegate += d3;

牛奶+报纸实例分析

为什么牛奶箱不能投递报纸?

代码

public interface IMilkBox

{

void PutMilkIn(string s);

}

public interface INewsPaperBox

{

void PutNewsPaperIn(string s);

}

public class Subscriber : INewsPaperBox, IMilkBox

{

public string name;

public Subscriber(string name)

{

this.name = name;

}

public void PutNewsPaperIn(string s)

{

Console.WriteLine("{0}在报箱里收到送来的{1}",name, s);

}

public void PutMilkIn(string s)

{

Console.WriteLine("{0}在奶箱里收到送来的{1}",name, s);

}

}

public class NewsPaperSender

{

protected ArrayList subscribers = new ArrayList();

public void SendNewsPaper()

{

foreach(INewsPaperBox newsPaperBox in subscribers)

newsPaperBox.PutNewsPaperIn("报纸");

}

public void Subscribe(INewsPaperBox newsPaperBox)

{

subscribers.Add(newsPaperBox);

}

}

public class MilkSender

{

protected ArrayList subscribers = new ArrayList();

public void SendMilk()

{

foreach(IMilkBox milkBox in subscribers)

milkBox.PutMilkIn("牛奶");

}

public void Subscribe(IMilkBox milkBox)

{

subscribers.Add(milkBox);

}

}

public class Client

{

public static void Main( string[] args )

{

MilkSender ms = new MilkSender();

NewsPaperSender nps = new NewsPaperSender();

Subscriber s1 = new Subscriber(“张三”);// s2,s3

ms.Subscribe(s1); ms.Subscribe(s2);

nps.Subscribe(s2);nps.Subscribe(s3);

ms.SendMilk(); nps.SendNewsPaper();

}

}

使用委托让牛奶报纸共享箱子

声明委托

public delegate void SendableDelegate(string s);

public class Subscriber //不用实现任何接口

public class NewsPaperSender

{

public event SendableDelegate SendNewsPaperHandler;

public void SendNewsPaper()

{

if(SendNewsPaperHandler != null)

SendNewsPaperHandler("报纸");

}

public void Subscribe(SendableDelegate sd)

{

SendNewsPaperHandler += sd;

}

}

public class Client

{

public static void Main( string[] args )

{

MilkSender ms = new MilkSender();

NewsPaperSender nps = new NewsPaperSender();

Subscriber s1 = new Subscriber(“张三”);//s2,s3

ms.Subscribe(new SendableDelegate(s1.PutMilkIn));

ms.Subscribe(new SendableDelegate(s2.PutMilkIn));

nps.Subscribe(new SendableDelegate(s2.PutNewsPaperIn));

nps.Subscribe(new SendableDelegate(s3.PutMilkIn));

ms.SendMilk(); nps.SendNewsPaper();

}

委托在多线程编程中的应用

皮特的故事