解析.Net 4.0 中委托delegate的使用详解
程序员文章站
2024-03-01 12:50:34
.net中的委托从功能上讲和c语言或者c++中的方法指针类似,可以像调用方法一样调用委托完成某个功能,或返回某类结果。但是.net毕竟是更高级的语言,委托delegate也...
.net中的委托从功能上讲和c语言或者c++中的方法指针类似,可以像调用方法一样调用委托完成某个功能,或返回某类结果。但是.net毕竟是更高级的语言,委托delegate也更高级了,委托是一种数据接口,它包含调用目标和调用方法的指针;而在.net中定义的委托都继承自multicastdelegate即多播委托,所谓的多播委托是指可以包含多个调用方法的委托。
一. 先来看下委托的定义:
如下c#代码定义委托
public delegate void dosomething(int times);
委托的定义包含5个部分
1) public表示委托的可访问性
2) delegate关键字表示要定义一个委托
3) void表示委托定义方法的返回值
4) dosomething是委托的名字
5) (int times) 是委托方法的参数列表,此处的参数列表可以包括ref参数,也可以有out参数,同样也可以有parms可变数量参数;需要注意如果委托中有多个调用方法,使用out参数时只能返回委托最后执行成功的一个委托方法的计算值
在c#中定义委托非常简单,只比方法定义的返回值之前多一个delegate关键字即可。
可是我们知道所有的用户定义委托都继承自multicastdelegate;而multicastdelegate是一个类;所以自定义的委托肯定也是一个类;看下上述代码的il代码就可以证明我们的推断:
.class public auto ansi sealed delegates.dosomething
extends [mscorlib]system.multicastdelegate
{
// methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method dosomething::.ctor
.method public hidebysig newslot virtual
instance void invoke (
int32 times
) runtime managed
{
} // end of method dosomething::invoke
.method public hidebysig newslot virtual
instance class [mscorlib]system.iasyncresult begininvoke (
int32 times,
class [mscorlib]system.asynccallback callback,
object 'object'
) runtime managed
{
} // end of method dosomething::begininvoke
.method public hidebysig newslot virtual
instance void endinvoke (
class [mscorlib]system.iasyncresult result
) runtime managed
{
} // end of method dosomething::endinvoke
} // end of class delegates.dosomething
二. 定义了委托,当然是为了使用它,来看下如何使用委托:
在.net中有三种委托的形式,分别是方法、匿名方法和lambda表达式;我们用方法定义的形式看下委托的使用方法
using system;
namespace delegates
{
public delegate void dosomething(int times);
class program
{
static void main(string[] args)
{
//声明委托变量并给委托变量赋值
dosomething @do = doa;
//可以使用+号或者+=给委托增加方法
@do += dob;
//执行委托时将按照委托的添加顺序先后执行委托中的方法
@do(1);
//也可以通过-号或者-= 从委托中移除方法
@do -= doa;
@do(2);
@do -= dob;
//将委托中的所有方法都移除掉之后,委托照样是可以调用的,只是什么都不做
@do(3);
console.read();
}
//定义一个委托相同参数和返回值的方法
static void doa(int times)
{
console.writeline("do a {0}", times);
}
//定义一个委托相同参数和返回值的方法
static void dob(int times)
{
console.writeline("do b {0}", times);
}
}
}
如上代码中的main方法,首先我们定义了委托dosomething的变量@do,并将doa方法直接赋值给此委托变量;然后我们又使用+=符号或者+号给此委托添加了另一个方法;当然也可以使用-或者-=从委托中去掉方法。
委托比c/c++方法指针强大的地方在于其可以容纳多个方法,也可以执行+/-操作从方法列表中添加或者删除掉方法。
在执行委托加减运算时有几个问题需要我们注意:
1. 委托声明的写法
委托声明时可以用如下写法
dosomething @do = doa;
这其实是一种简短的写法,我们知道在.net 1.x中这样写是不允许的只有到.net 2.0时才允许这么写,在.net 1.x中必须写成
dosomething @do = new dosomething(doa);
我们要在声明时就给@do赋予doa加上dob
dosomething @do = doa + dob;
这么写是不行的,编译器不干了;必须使用.net 1.x中的写法
dosomething @do = new dosomething(doa) + new dosomething(dob);
2. 从委托中减去委托中本不存在的方式时会发生什么呢?
请看如下代码:
dosomething @do = doa;
@do -= dob;
第一行代码我生命了@do并将doa赋予它;第二行代码我尝试从@do中减去dob,dob并没有在@do的方法列表中存在,这样会发生什么情况呢?首先编译器没有报错,程序可以正常的编译;执行代码发现可以程序可以正常执行,调用@do委托时正确的执行了doa方法;这说明了.net包容了我们程序员犯的错,我们从委托变量中减去一个委托中并不包含的方法时,不会报错会正常的执行。
3. 对委托做减法,所有委托都减完了,会怎样呢?看如下代码
dosomething @do = new dosomething(doa) + new dosomething(dob);
@do -= doa;
@do -= dob;
@do(1);
这样的代码可以成功编译,但是在运行时会报nullreferenceexception;这显然不是我们希望的,所以对委托做减法时要特别注意。
<span style="text-decoration: line-through;">public delegate void doit(string task);
class test
{
static void main(string[] args)
{
//doit声明,赋予一个参数更宽泛的方法是合法的
doit doit = new doit(doitimpl);
doit("hello");
}
//比委托定义中的参数更宽泛,string类型可以隐式转换成object
static void doitimpl(object task)
{
console.writeline("doitimpl {0}",task);
}
}
</span>
一. 先来看下委托的定义:
如下c#代码定义委托
public delegate void dosomething(int times);
委托的定义包含5个部分
1) public表示委托的可访问性
2) delegate关键字表示要定义一个委托
3) void表示委托定义方法的返回值
4) dosomething是委托的名字
5) (int times) 是委托方法的参数列表,此处的参数列表可以包括ref参数,也可以有out参数,同样也可以有parms可变数量参数;需要注意如果委托中有多个调用方法,使用out参数时只能返回委托最后执行成功的一个委托方法的计算值
在c#中定义委托非常简单,只比方法定义的返回值之前多一个delegate关键字即可。
可是我们知道所有的用户定义委托都继承自multicastdelegate;而multicastdelegate是一个类;所以自定义的委托肯定也是一个类;看下上述代码的il代码就可以证明我们的推断:
复制代码 代码如下:
.class public auto ansi sealed delegates.dosomething
extends [mscorlib]system.multicastdelegate
{
// methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method dosomething::.ctor
.method public hidebysig newslot virtual
instance void invoke (
int32 times
) runtime managed
{
} // end of method dosomething::invoke
.method public hidebysig newslot virtual
instance class [mscorlib]system.iasyncresult begininvoke (
int32 times,
class [mscorlib]system.asynccallback callback,
object 'object'
) runtime managed
{
} // end of method dosomething::begininvoke
.method public hidebysig newslot virtual
instance void endinvoke (
class [mscorlib]system.iasyncresult result
) runtime managed
{
} // end of method dosomething::endinvoke
} // end of class delegates.dosomething
二. 定义了委托,当然是为了使用它,来看下如何使用委托:
在.net中有三种委托的形式,分别是方法、匿名方法和lambda表达式;我们用方法定义的形式看下委托的使用方法
复制代码 代码如下:
using system;
namespace delegates
{
public delegate void dosomething(int times);
class program
{
static void main(string[] args)
{
//声明委托变量并给委托变量赋值
dosomething @do = doa;
//可以使用+号或者+=给委托增加方法
@do += dob;
//执行委托时将按照委托的添加顺序先后执行委托中的方法
@do(1);
//也可以通过-号或者-= 从委托中移除方法
@do -= doa;
@do(2);
@do -= dob;
//将委托中的所有方法都移除掉之后,委托照样是可以调用的,只是什么都不做
@do(3);
console.read();
}
//定义一个委托相同参数和返回值的方法
static void doa(int times)
{
console.writeline("do a {0}", times);
}
//定义一个委托相同参数和返回值的方法
static void dob(int times)
{
console.writeline("do b {0}", times);
}
}
}
如上代码中的main方法,首先我们定义了委托dosomething的变量@do,并将doa方法直接赋值给此委托变量;然后我们又使用+=符号或者+号给此委托添加了另一个方法;当然也可以使用-或者-=从委托中去掉方法。
委托比c/c++方法指针强大的地方在于其可以容纳多个方法,也可以执行+/-操作从方法列表中添加或者删除掉方法。
在执行委托加减运算时有几个问题需要我们注意:
1. 委托声明的写法
委托声明时可以用如下写法
复制代码 代码如下:
dosomething @do = doa;
这其实是一种简短的写法,我们知道在.net 1.x中这样写是不允许的只有到.net 2.0时才允许这么写,在.net 1.x中必须写成
复制代码 代码如下:
dosomething @do = new dosomething(doa);
我们要在声明时就给@do赋予doa加上dob
复制代码 代码如下:
dosomething @do = doa + dob;
这么写是不行的,编译器不干了;必须使用.net 1.x中的写法
复制代码 代码如下:
dosomething @do = new dosomething(doa) + new dosomething(dob);
2. 从委托中减去委托中本不存在的方式时会发生什么呢?
请看如下代码:
复制代码 代码如下:
dosomething @do = doa;
@do -= dob;
第一行代码我生命了@do并将doa赋予它;第二行代码我尝试从@do中减去dob,dob并没有在@do的方法列表中存在,这样会发生什么情况呢?首先编译器没有报错,程序可以正常的编译;执行代码发现可以程序可以正常执行,调用@do委托时正确的执行了doa方法;这说明了.net包容了我们程序员犯的错,我们从委托变量中减去一个委托中并不包含的方法时,不会报错会正常的执行。
3. 对委托做减法,所有委托都减完了,会怎样呢?看如下代码
复制代码 代码如下:
dosomething @do = new dosomething(doa) + new dosomething(dob);
@do -= doa;
@do -= dob;
@do(1);
这样的代码可以成功编译,但是在运行时会报nullreferenceexception;这显然不是我们希望的,所以对委托做减法时要特别注意。
复制代码 代码如下:
<span style="text-decoration: line-through;">public delegate void doit(string task);
class test
{
static void main(string[] args)
{
//doit声明,赋予一个参数更宽泛的方法是合法的
doit doit = new doit(doitimpl);
doit("hello");
}
//比委托定义中的参数更宽泛,string类型可以隐式转换成object
static void doitimpl(object task)
{
console.writeline("doitimpl {0}",task);
}
}
</span>