如果匿名委托没有访问所在函数的局部变量,匿名委托会被自动生成为一个静态的函数(
Lambda可以认为是一种特殊语法形式的匿名委托
- counter.CountChangedHandlers = i => System.Console.WriteLine("count={0}", i);
1.4 多路广播
委托可以支持多路广播,也就是可以使用“+=”操作符注册多个回调函数。委托可以支持多路广播,也就是可以使用“+=”操作符注册多个回调函数。使用“+=”或“-=”时不用担心委托变量为null的情况会出现空指针异常。
Code:
-
static void Main(string[] args)
-
{
-
Counter counter = new Counter();
-
counter.CountChangedHandlers += PrintHandler;//这里也可使用“=”
-
counter.CountChangedHandlers += PrintHandler;
-
-
counter.add();
-
counter.add();
- }
count=1
count=1
count=2
count=2
上面把同一个函数注册了2次,所以也就会被调用2次。
使用“-=”操作符可以删除已注册的回调函数。
Code:
-
static void Main(string[] args)
-
{
-
Counter counter = new Counter();
-
-
CountChangedHandler h = new CountChangedHandler(PrintHandler);
-
counter.CountChangedHandlers += h;
-
counter.CountChangedHandlers += h;
-
counter.CountChangedHandlers -= h;
-
-
counter.add();
-
counter.add();
- }
count=1
count=2
上面注册了2次,删除了1次,所以最后被调用了1次。
1.5 异步调用委托
委托还可以被异步调用
Code:
-
public void add()
-
{
-
count++;
-
if (CountChangedHandlers != null)
-
{
-
IAsyncResult iAsyncRslt = CountChangedHandlers.BeginInvoke(count, null, null);
-
System.Console.WriteLine("delegate call begin");
-
CountChangedHandlers.EndInvoke(iAsyncRslt);
-
System.Console.WriteLine("delegate call end");
-
}
- }
delegate call begin
count=1
delegate call end
delegate call begin
count=2
delegate call end
1.6 委托的实现
通过ildasm查看由委托生成的代码,可以发现编译后声明的委托类型变成了一个继承自MulticastDelegate的类,并提供了几个调用委托的方法。
2. 事件
2.1 概述
在常用的事件监听应用场景下,被监听的对象只需要提供监听回调函数的注册和删除方法。而委托对象提供的功能太多,不宜公开,应该通过private修饰符隐藏起来。
比如像下面这样。
Code(修改前):
- public CountChangedHandler CountChangedHandlers;
-
private CountChangedHandler CountChangedHandlers;
-
-
public void RegisterCountChangedHandler(CountChangedHandler handler)
-
{
-
CountChangedHandlers += handler;
-
}
-
-
public void UnRegisterCountChangedHandler(CountChangedHandler handler)
-
{
-
CountChangedHandlers -= handler;
- }
然而如果在每个事件监听应用场景下都这么写不免繁琐,event就是解决这个问题的好办法。只要在原来声明委托对象的地方使用event关键字加以修饰,编译器就会自动做类似上面的事。被event关键字修饰后,在Counter对象外部只能通过"+="和"-="对事件注册或者删除监听回调函数,在Counter对象内部仍然可以像原来一样使用委托对象。
使用event后的完整代码示例如下:
Code:
点击(此处)折叠或打开
-
namespace Sample
-
{
-
public delegate void CountChangedHandler(int count);
-
-
public class Counter
-
{
-
private int count = 0;
-
public event CountChangedHandler CountChangedHandlers;
-
-
public void add()
-
{
-
count++;
-
if (CountChangedHandlers != null)
-
CountChangedHandlers(count);
-
}
-
}
-
-
class Program
-
{
-
static void PrintHandler(int count)
-
{
-
System.Console.WriteLine("count={0}", count);
-
}
-
-
static void Main(string[] args)
-
{
-
Counter counter = new Counter();
-
counter.CountChangedHandlers += new CountChangedHandler(PrintHandler);
-
-
counter.add();
-
counter.add();
-
}
-
}
- }
2.2 事件的实现
通过ildasm查看编译后的代码,可以更清晰发现加与不加event的区别。加了event关键字后,委托对象变成了private的,并且自动生成了一个和委托对象同名的事件。
没有event关键字时:
public CountChangedHandler CountChangedHandlers;
有event关键字时:
public event CountChangedHandler CountChangedHandlers;