C Sharp/Delegates and Events
介绍
编辑委托(delegate)与事件(event)是Windows或Web应用程序的基础。委托基本上相当于C语言的函数指针;委托数据告诉C#一个事件被触发时哪些方法被调用。事件是.NET framework通知某个动作发生了;事件包含了特定信息,如鼠标点击事件包含了哪个鼠标按键在窗体的哪里被点击。
委托
编辑委托是一个结构,可引用一个方法,该方法以后可被调用。一个委托的声明指示特定的方法签名。一个或更多个方法的引用可以增添到一个委托实例上。委托实例可以被调用,实际上是该委托实例引用的所有方法按照加入该委托的次序被调用。一个简单例子:
using System;
delegate void Procedure();
class DelegateDemo
{
public static void Method1()
{
Console.WriteLine("Method 1");
}
public static void Method2()
{
Console.WriteLine("Method 2");
}
public void Method3()
{
Console.WriteLine("Method 3");
}
static void Main()
{
Procedure someProcs = null;
someProcs += new Procedure(DelegateDemo.Method1);
someProcs += new Procedure(Method2); // Example with omitted class name
DelegateDemo demo = new DelegateDemo();
someProcs += new Procedure(demo.Method3);
someProcs();
}
}
上例中,delegate void Procedure();
是一个委托的声明,该语句是完全抽象,不会产生可执行代码,仅仅是声明Procedure
为一个无参、返回为空的委托类型。
已被委托引用的方法可以删除引用:
someProcs -= new Procedure(DelegateDemo.Method1);
从C# 2.0,增加或删除方法引用可用更简明的语法:
someProcs += DelegateDemo.Method1;
someProcs -= DelegateDemo.Method1;
调用一个没有引用任何方法的委托,导致NullReferenceException。
注意,如果委托返回特定类型的结果,那么调用一个引用了多个方法的委托,实际返回的是最后被执行的方法的结果。
匿名委托
编辑匿名委托是使用delegate关键字写出委托的代码,可以捕获局部变量,被编译器自动转化为方法。例如:
using System;
delegate void Procedure();
class DelegateDemo2
{
static Procedure someProcs = null;
private static void AddProc()
{
int variable = 100;
someProcs += new Procedure(delegate
{
Console.WriteLine(variable);
});
}
static void Main()
{
someProcs += new Procedure(delegate { Console.WriteLine("test"); });
AddProc();
someProcs();
Console.ReadKey();
}
}
可以如普通方法一样接受参数:
using System;
delegate void Procedure(string text);
class DelegateDemo3
{
static Procedure someProcs = null;
private static void AddProc()
{
int variable = 100;
someProcs += new Procedure(delegate(string text)
{
Console.WriteLine(text + ", " + variable.ToString());
});
}
static void Main()
{
someProcs += new Procedure(delegate(string text) { Console.WriteLine(text); });
AddProc();
someProcs("testing");
Console.ReadKey();
}
}
输出为:
testing testing, 100
Lambda表达式
编辑Lambda表达式是比匿名委托更为清晰的方式。语法为:
(type1 arg1, type2 arg2, ...) => expression
这等价于:
delegate(type1 arg1, type2 arg2, ...)
{
return expression;
}
如果只有一个参数,则圆括号可省略。参数类型也可以省略,让编译去去推导。例如:
Func<string, int> myFunc = str => int.Parse(str);
这等效于:
Func<string, int> myFunc = delegate(string str)
{
return int.Parse(str);
};
事件
编辑事件是一种特殊的委托,用于事件驱动编程。事件可以是类从成员,但即使其访问指示符是public,事件只能在包含它的类中被调用,但在其它类可以为事件增加或减少方法引用。例如:
public delegate void ButtonClickedHandler();
class Button
{
public event ButtonClickedHandler ButtonClicked;
ButtonClicked += ()=>{Console.WriteLine("click simulation !")};
public void SimulateClick()
{
if (ButtonClicked != null)
{
ButtonClicked();
}
}
...
}
在其它类中的方法可以通过向该事件委托增加方法,来订阅到该事件:
Button b = new Button();
b.ButtonClicked += ButtonClickHandler;
private void ButtonClickHandler()
{
//Handle the event
}
即使这个事件被声明为public,它之恶能在包含它的类中被直接fire。