from.;http://www.cnblogs.com/OpenCoder/archive/2009/09/23/1572646.html
委托给了C#操作函数的灵活性,我们可使用委托像操作变量一样来操作函数,其实这个功能并不是C#的首创,早在C++时代就有函数指针这一说法,而在我看来委托就是C#的函数指针,首先先简要的介绍一下委托的基本知识:
1.委托的定义
委托的声明原型是
delegate <函数返回类型> <委托名> (<函数参数>)
例子:
public delegate void CheckDelegate(int number);//定义了一个委托CheckDelegate,它可以注册返回void类型且有一个int作为参数的函数
这样就定义了一个委托, 但是委托在.net内相当于声明了一个类(在后面的代码中会讲到确实如此),类如果不实例化为对象,很多功能是没有办法使用的,委托也是如此.
2.委托的实例化
委托实例化的原型是
<委托类型> <实例化名>=new <委托类型>(<注册函数>)
例子:
CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//用函数CheckMod实例化上面的CheckDelegate 委托为_checkDelegate
在.net 2.0开始可以 直接用匹配的函数实例化委托:
<委托类型> <实例化名>=<注册函数>
例子:
CheckDelegate _checkDelegate=CheckMod;//用函数CheckMod实例化上面的CheckDelegate 委托为_checkDelegate
现在我们就可以像使用函数一样来使用委托了,在上面的例子中现在执行_checkDelegate()就等同于执行CheckMod(),最关键的是现在函数CheckMod相当于放在了变量当中,它可以传递给其它的CheckDelegate引用对象,而且可以作为函数参数传递到其他函数内,也可以作为函数的返回类型
3.用匿名函数初始化委托
上面为了初始化委托要定义一个函数是不是感觉有点麻烦,另外被赋予委托的函数一般都是通过委托实例来调用,很少会直接调用函数本身。
在.net 2.0的时候考虑到这种情况,于是匿名函数就诞生了,由于匿名函数没有名字所以必须要用一个委托实例来引用它,定义匿名函数就是为了初始化委托
匿名函数初始化委托的原型:
<委托类型> <实例化名>=new <委托类型>(delegate(<函数参数>){函数体});
当然在.net 2.0后可以用:
<委托类型> <实例化名>=delegate(<函数参数>){函数体};
例子:
delegate void Func1(int i);
delegate int Func2(int i);
static Func1 t1 =new Func1(delegate(int i)
{
Console.WriteLine(i);
});
static Func2 t2;
static void Main(string[] args)
{
t2 = delegate(int j)
{
return j;
};
t1(2);
Console.WriteLine(t2(1));
}
当然在.net 3.0的时候又有了比匿名函数更方便的东西lambda表达式,这儿就不说了。
4.泛型委托
委托也支持泛型的使用
泛型委托原型:
delegate <T1> <委托名><T1,T2,T3...> (T1 t1,T2 t2,T3 t3...)
例子:
delegate T2 A<T1,T2>(T1 t);//定义有两个泛型(T1,T2)的委托,T2作为委托函数返回类型,T1作为委托函数参数类型
static int test(int t)
{
return t;
}
static void Main(string[] args)
{
A<int, int> a =test;//将泛型委托委托<T1,T2>实例化为<int,int>,即表示有一个int类型参数且返回类型是int的函数,所以将test用来实例化委托
Console.WriteLine(a(5));//输出5
}
5.委托的多播性
在上面实例化委托的时候看到:必须将一个匹配函数注册到委托上来实例化一个委托对象,但是一个实例化委托不仅可以注册一个函数还可以注册多个函数,注册多个函数后,在执行委托的时候会根据注册函数的注册先后顺序依次执行每一个注册函数
函数注册委托的原型:
<委托类型> <实例化名>+=new <委托类型>(<注册函数>)
例子:
CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//将函数CheckMod注册到委托实例_checkDelegate上
在.net 2.0开始可以直接将匹配的函数注册到实例化委托:
<委托类型> <实例化名>+=<注册函数>
例子:
CheckDelegate _checkDelegate+=CheckMod;//将函数CheckMod注册到委托实例_checkDelegate上
之后我们还可以注册多个函数到委托上:例子:
_checkDelegate+=CheckPositive;//将函数CheckPositive注册到委托实例_checkDelegate上
_checkDelegate();//执行这个委托实例会先执行CheckMod()再执行CheckPositive()
实际上使用+=符号的时候会判断
如果此时委托还没有实例化(委托实例为null),它会自动用+=右边的函数实例化委托
如果此时委托已经实例化,它会只把+=右边的函数注册到委托实例上
另外有一点需要注意的是,如果对注册了函数的委托实例从新使用=号赋值,相当于是重新实例化了委托,之前在上面注册的函数和委托实例之间也不再产生任何关系,后面的例子会讲到这点!
当然有+=注册函数到委托,也有-=解除注册
例子:_checkDelegate-=new CheckDelegate(CheckPositive);//解除CheckPositive对_checkDelegate的注册
_checkDelegate-=CheckPositive;//.net 2.0开始可以用这种方式解除注册
另外当在委托和事件(事件的细节将在后面介绍)上注册了多个函数后,如果委托和事件有返回值,那么调用委托和事件时,返回的将是最后一个注册函数的返回值。如下示例代码将做详细解释。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiDelegatesReturn
{
public delegate int DelMath(int i);//定义委托类DelMath,该委托传入一个int类型参数,返回一个int类型参数
class Program
{
static DelMath dMath;//通过委托类型DelMath定义委托实例dMath
static event DelMath eMath;//通过委托类型DelMath定义事件实例eMath
/// <summary>
/// 将传入的参数i自加后作为函数返回值
/// </summary>
static int IncMath(int i)
{
i++;
Console.WriteLine("IncMath has been invoked!");
return i;
}
/// <summary>
/// 将传入的参数i自减后作为函数返回值
/// </summary>
static int DecMath(int i)
{
i--;
Console.WriteLine("DecMath has been invoked!");
return i;
}
static void Main(string[] args)
{
int i = 10;//定义int型变量i,初始值为10
dMath += IncMath;//先将IncMath函数注册到委托实例dMath
dMath += DecMath;//再将DecMath函数注册到委托实例dMath
Console.WriteLine("dMath returned:" + dMath(i).ToString());//将int型变量10传入委托实例dMath调用后,返回的结果是9,说明委托实例
//dMath返回的是后注册的函数DecMath的返回值
eMath += IncMath;//先将IncMath函数注册到事件实例eMath
eMath += DecMath;//再将DecMath函数注册到事件实例eMath
Console.WriteLine("eMath returned:" + eMath(i).ToString());//将int型变量10传入事件实例eMath调用后,返回的结果也是9,说明事件实例
//eMath返回的也是后注册的函数DecMath的返回值
}
}
}