委托
委托相当于C语言当中的函数指针,不过委托是类型安全的类,它定义了返回类型和参数的类型。
声明委托
在C#中使用一个类,分为两个阶段。首先,需要定义这个类,告诉编译器这个类由什么字段和方法组成,然后实例化这个类的一个对象。使用委托也要经过这两个步骤。首先,定义要使用的委托(类),告诉编译器这委托(类)表示的是哪种类型的方法,然后创建委托的实例。它们都是要即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。
//定义IntMethodInvoker委托类
delegate void IntMethodInvoker(int x);
static void Main(string[] args)
{
//创建IntMethodInvoker委托实例,并把Method1方法委托给invoker
IntMethodInvoker invoker = new IntMethodInvoker(Method1);
invoker();
} static void Method1(int i)
{
Console.Write(i);
}
定义委托类似于方法的定义,但没有方法体,定义的前面要加关键字delegate。委托相当类,所以可以在定义类的任何地方定义委托,也就是说可以在类外部,也可以在类内部定义,当然也可以在委托定义上使用任意的访问修饰符。定义委托类型时就指明了该委托类型的实例所能接受的方法的返回类型和其参数。例如上例中的IntMethodInvoker委托类的实例就只能接受只有一个int参数及返回为空的方法。执行委托实例跟执行方法一样,直接在委托实例后加括号,并在括号中填入该委托所对应参数。
实际上,给委托实例提供圆括号与调用委托类的hvoke()方法完全相同,C#编译器会用invoke.invoke(3)代替invoker(3)。
上面声明实例对象时,也可以简写为下面方式,注意Method1后面没有括号。
IntMethodInvoker invoker =Method1
给定委托的实例可以作用任何类型的任何对象的实例方法或静态方法,只要方法的签名匹配于委托的签名即可。
Action(T)和Func(T)委托
除了我们自己定义委托类型,微软的类库中也为我们内置Action<T>和Func<T>的泛型委托,这样就可以免得我们自己去定义委托类型了,我们可以直接使用内置的委托类型。
泛型Action<T>委托表示引用一个void返回类型的方法,该委托内存在不同的变体,它最多可传递16 个参数。非泛型Action委托类型可以调用带无返回类型且无参数的方法。
Func<T>委托类似于Action<T>委托,不同的是Func<T>调用的是带有返回类型的方法。Func<T>也定义了不同的变体,它最多可以传递16个参数和一个返回类型。Func<out TResult>委托类型可以调用带返回类型且无参数的方法。
匿名方法
最直接的理解就没有名称的方法,例如我们给最上面的例子中的IntMethodInvoker委托实例invoker委托一个方法,我们可以像下面一样写,这样我们就不用另外去定义一个方法了。
invoker = delegate(int param)
{
Console.Write(param);
};
如果委托类型是定义有返回类型的话,就直接在匿名方法体最后返回指定类型的值就可以了。
Lambda表达式
上面使用用匿名方法的例子可以改为使用Lambda表达式:
invoker = param =>
{
Console.Write(param);
};
lambda运算符"=>"的左边列出了需要的参数,lambda运算符右边则写方法的实现代码。
如果lambda表达式只有一个参数,就直接写参数名就可以了,如上例。如果有多个参数则用括号括起来,每个参数之间用逗号隔开。当然在每个参数前面我们可以为参数添加类型:
invoker =(string param )=>
{
Console.Write(param);
};
事件
事件是基于委托的,为委托提供了一种发布/订阅机制。
delegate void Mydelegate(int a);
event Mydelegate MyEvent;
声明事件使用关键字event。上面我们只用一行就定义了一个事件,其实这只是C#的一个语法糖。这非常类似于自动属性和完整属性之间的关系。对于事件,使用add和remove关键字添加和删除委托的处理程序:
private Mydelegate myEvent;
public event Mydelegate MyEvent
{
add
{
this.myEvent= (Mydelegate)Delegate.Combine(this.myEvent, value);
}
remove
{
this.myEvent= (Mydelegate) Delegate.Remove(this.myEvent, value);
}
}
事件其实就是在内部把一个委托实例封装起来,向外只提供注册和注销方法。