欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

委托的发展(一)

程序员文章站 2022-04-08 15:41:59
zzz这几天一直在看委托, 一直从1.0的委托看到了3.0的兰姆达表达式与linq。 写个博客记录一下,虽然委托的多种用法都没有研究透彻,以后慢慢研究吧! 先说说c#1.0委托怎么使用吧!毕竟要从起源开始讲起! 一提起委托,如果你是c程序员,肯定会想到 函数指针 这个术语.实际上委托在某种程度上提供 ......

zzz这几天一直在看委托,

一直从1.0的委托看到了3.0的兰姆达表达式与linq。

写个博客记录一下,虽然委托的多种用法都没有研究透彻,以后慢慢研究吧!

先说说c#1.0委托怎么使用吧!毕竟要从起源开始讲起!

一提起委托,如果你是c程序员,肯定会想到 函数指针 这个术语.实际上委托在某种程度上提供了间接的方法。

换言之,不需要直接指定一个要执行的行为,而是将这个行为用某种方式"包含"在一个对象中。这个对象可以像其他任何的对象那样使用,再该对象中,可以执行封装的操作。

可以选择将委托类型看做之定义了一个方法的接口,将委托的实例看做实现了那个接口的一个对象。

简单委托的构成,为了让委托做某事,必须满足四个条件:

*声明委托类型

*必须有一个方法包含了要执行的代码;

*必须创建一个委托实例

*必须调用(Invoke)委托实例

慢慢来,一个个的看:

*声明委托类型

委托类型实际上只是参数类型的一个列表以及一个返回类型。他规定了类型的实例能表示的操作。

例如:

delegate void StringDelegate(string val);

这段代码指出,如果要创建 StringDelegate 这样一个实例,必须要只带一个参数(string),并且无返回值 void 方法。

*为委托实例的操作找一个恰当的方法

基本思路就是,要确保在调用Invoke一个委托实例时,使用的参数完全匹配,而且以我们希望的方式返回值(如果有的话)。

     void Test1(string x);
        void Test2(int x);
        void Test3(string x, string y);
        int  Test4(string x);
        void Test5(object x);

这些个方法有那几个满足呢?

首先Test1完全符合要求,所以用它创建一个委托实例。

第二个Test2虽然也有一个参数但是不是String类型的,所以不兼容。

第三个Test3参数数量不匹配,不兼容。

第四个Test4参数类型个数匹配,但返回类型不是void,所以不兼容。

第五个就比较有意思了,返回类型匹配,但是参数类型不是String 而是 Object,大家都知道String是由Object派生的。把这个方法作为一个委托实例应该合情合理啊!

但是C#1要求委托必须具有完全相同的参数类型。所以在C#1中这个也是不兼容的!

*创建委托实例

如果给委托加入一个实例,首先他必须与委托有相同的返回值,参数个数,参数类型 必须一致。

至于具体用什么形式的表达式来创建委托实例,取决于操作的实例方法还是静态方法。

实例方法:

 InstanceMethods instance = new InstanceMethods(); //实例化
 StringDelegate DelegateStr = new StringDelegate(instance.Methods);//委托实例化

静态方法:

StringDelegate DelegateStr = new StringDelegate(StaticMethods.Mehtods);

如果是静态方法,指定类型名称就可以了。如果是实例方法,就必须先创建类型(或者他的派生类型)的一个实例。和平时调用方法是一样的,这个对象被称为操作的目标。

单纯创建一个委托实例却不在某一刻调用他是么有什么意义的,具体看看最后一步-----调用。

*调用委托实例

这是一件很容易的事儿,调用一个委托实例的方法就可以了.这个方法被称为Invoke(百度翻译:乞灵,祈求;提出或授引…以支持或证明;召鬼;借助)

在委托类型中这个方法以委托类型的形式出现,并且具有委托类型声明中指定的相同参数列表和返回类型。

所以,在我们的例子中,有一个这样的方法:

 void Invoke(string val)

调用Invoke会执行委托实例的操作,向他传递在调用Invoke时指定的任何参数。另外如果返回值不是void,还要返回操作的返回值。

很简单不是吗?如果有一个委托类型的变量,就可以把它视为方法本身。观察者有不同时间发生的事件构成一个时间链,就很容易理解这一点。

委托的发展(一)

c#1的委托就是这么简单!所有原料已经齐备,接着将CLR预热到200°C,将所有东西搅拌在一起,看看会发生什么。

对了忘记给大家说一下委托的添加实例与删除实例了。。。

System.Delegate类型的静态方法Combine和Remove负责创建新的委托实例。

其中Combine负责将两个委托的调用列表连接到一起(就是添加一个实例)

而Remove负责从一个委托实例中删除另一个实例的调用列表(就是删除一个实例)

现在很少在C#代码中看到Delegate.Combine的显示调用了,大家一般都这样写+=跟-=操作符

其实运行的时候会转换成Delegate.Combine,看一下下面的x委托加入y实例

委托的发展(一)

一个非常简单的转换过程,但它使代码变得整洁多了。

除了合并添加实例,也可以删除实例使用Delegate.Remove方法删除一个指定的实例,平时都是用简写-=来实现。

调用委托实例时,他的所有操作都顺序执行。如果委托的签名是一个非void的返回类型的话。

则Invoke的返回值是 最后一个 操作的返回值。

如果调用列表中的任何一个操作抛出异常,都会阻止后续的操作。

例如调用一个委托,他的操作列表是[a,b,c],但是b抛出了异常,这个异常会立刻传播,操作c不会执行。

总结一下C#1的委托吧

*委托封装了包含特殊返回类型和一组参数的行为,类似包含单一方法的接口。

*委托类型声明中所描述的类型签名决定了哪个方法可用于创建委托实例。同时决定了调用的签名

*为了创建委托实例,需要一个方法以及(对于实例方法来说)调用的目标。

*委托实例都包含一个调用列表-----一个操作列表

*委托实例可以合并到一起,也可以从一个委托实例中删除另一个

*事件不是委托的实例,只是成对的add/remove方法(类似于属性的取值方法/赋值方法)