委托
一.委托的概念:
>委托是C#中有用户自定义的一个类型(和普通的类差不多)
>类表示的是数据和方法的集合,而委托实际上是只持有方法的引用
>委托类能拥有一个签名,并且它只能持有与它的签名相匹配的方法的调用
二.如何使用委托:
>声明一个委托类型
>使用该委托类型声明一个委托变量
>创建委托类型的对象,把它赋值给委托变量。该委托对象包含某个方法的引用,这个方法和第1步定义的签名一致
>为委托对象增加其他方法
>像调用方法一样调用委托。此时,委托持有的每一个方法都会依次执行
三.如何声明委托:
举个例子:声明普通方法:public void TestMethod(int num){num=10;}
声明委托类:public delegate void TestDelegate(int num);
可以看到:
1>声明委托的语法与定义方法的语法类似,但没有立法体,且生命前应该加上关键字delegate;
2>声明委托相当于声明一个新类,所以可以在任何声明类的相同地方声明委托;
3>可以在委托声明上应用访问修饰符 如public、private等
四、创建委托对象
方法一:使用带new运算符的对象创建表达式
eg: TestDelegate td1= new Test Delegate(TestMethod);
方法二:直接用方法名进行创建
eg:TestDelegate td2=TestMethod;
※方法可以来自任何类和结构,可以是实例方法,也可以是静态方法,但方法签名必须和委托签名一致。
※可以通过赋值来改变包含在委托变量中的引用,旧的委托对象会被垃圾回收器回收。
五、委托的调用
和方法的调用一样;
六、委托数组
每个元素都是一个委托的对象,与普通数组用法相同
eg:TestDelegate[ ] delegateArray={test1, test2,test3}
七、组合委托
委托可以使用“+”运算符来组合,这个运算最终会创建一个新的委托,其调用列表连接了作为操作数的两个委托的调用列表副本
eg:
MyDel delA = mylnstObj.MyM1;
MyDel delB = SClass.OtherM2
MyDel delC = delA + delB;
八、委托上方法的添加和移除
1.添加方法:使用“+=”运算符
>在使用“+=”运算符时,实际上发生的是创建了一个新的委托,其调用列表是左边的委托加上右边方法的组合。然后将这个新的委托重新赋值给原委托变量。此时原委托变量就指向了一个全新的委托。
eg: gd1+=edg.TestMethod;(原委托上的调用列表加上新方法,成为一个新的委托)
2.移除方法:使用“-=”运算符
>与增加方法相同,也是创建了一个新的委托如果调用列表中同一个方法有多个,-=运算符将从列表末尾开始搜索,并且移除第个匹配的方法。
>试图移除委托中不存在的方法没有效果
>试图调用空委托会抛出异常。 ( null )
eg: gd1-=edg.TestMethod;(与增加方法相同,在原委托上的调用列表上减去方法,成为一个新委托)
事件
一、简述事件:
举一个手机上的例子,经由事件发送出来的与事件本身相关的数据(消息),称之为事件参数(Event Args);
某某对象拥有一个事件意思为这个对象可以通过这个时间来通知别的对象。事件发生时,别的关注这个事件的对象们就会依次被通知到,纷纷做出响应
事件的定义:“能够发生的什么事情”
事件的角色:使对象或类具备通知能力的成员
简单来说事件的功能就是:通知
事件成员的功能=通知+可选的事件参数
事件的用法:决定类或对象之间的动作协调与信息传递
事件是一种思想
事件模型的五个部分组成
1.事件的拥有者(event source,对象或一个类)
2.事件成员(event,成员)
3.事件的响应者(event handler,对象或一个类)==事件的订阅者,事件消息的接收者,事件的处理者,被事件所通知的对象
4.事件处理器(event handler,成员)——本质上是一个回调方法,是事件响应者身上的一个方法成员
5.事件订阅——把事件处理器与事件关联在一起,本质上是一种以委托类型为基础的“约定”。所以说事件是基于委托的。(通过委托约束了事件将什么消息可以发送给事件处理器,且也约束了事件处理器可以处理什么消息,如果他们同时遵从了统一约定则可以订阅)
6.事件信息==事件消息==事件数据==事件参数
二、使用事件
注意:注册一个事件时,注册的方法只需要一个方法名,因为加上括号表示要调用这个方法
第二种注册事件的方法:
使用匿名方法直接挂接事件。匿名方法:别处没办法引用这个方法
第三种Lambda表达式:为了取代上面第二种方法:
甚至可以省略参数类型,由vs自动推断出类型
小扳手表示的是属性,小方块小盒子表示的是方法,小闪电表示的是事件
存储数据,做事情,通知别人
自定义一个委托类型用来声明事件
一、委托和事件之间的关系
1.事件是基于委托的,意味着事件是需要委托作为约束的
2.委托是一种数据类型,和类一样,委托是对方法的抽象,类是对对象的抽象
3.事件无论从表层约束,底层实现来讲都是依赖于委托类型的
4.如果声明的委托是为了声明的某个事件做准备,则需要将委托名加上“EventHandler”作为后缀,用于传输事件消息的类名需要加上“EventArgs”并继承“EventArgs"
eg:事件参数:事件名“Order”加上Args,委托类型:OrderEventHandler:用于声明Order事件
5.事件的普通声明和简化声明:
普通声明:将外界在Order传进来的方法注册到委托字段上
简化声明:
二者是相等的,只不过上面我们手动声明的委托类型字段被隐藏声明了。
简化声明后调用这个事件:
6.为什么有了委托字段/属性,还需要事件??
答:因为事件的本质是委托字段的一个包装器,本质上是为了保护委托字段
注:事件其实可以说是封装了一个委托
事件成员可以隐藏委托实例的大部分功能,比如Invoke()和判断是否为空,限制了外界访问委托
7.最最常用的用于声明事件的委托:EventHandler
而对于EventHandler这个委托微软官方是这样定义的
使用EventHandler委托作为事件的声明就可以省去下面这些自己编写一个委托:
所以事件的触发器需要进行一下格式转换
8.命名规则,用于声明事件的委托类型的命名约定:
1.1用于声明Foo事件的委托,一般命名为FooEventHandler(除非是上面提到的EventHandler)
1.2FooEventHandler委托的参数一般有两个:(微软将事件委托的参数列表当作事件消息来看)
1.2.1 第一个是object类型,名字为sender(事件的拥有者)表示谁把消息发过来的。
1.2.2第二个是EventArgs类的派生类,类名一般为FooEventArgs,参数名为e(事件参数),里面存储的是关于事件的一些数据。
1.2.3虽然官方没有说,但是我们可以把委托的参数列表看做是事件发生后发送给事件响应者的“事件消息”
1.3触发Foo事件的方法一般命名为OnFoo,即“因何引发”、“事出有因”
1.3.1访问级别为protected,不能为public,不然又成了可以“借刀杀人”了。
1.4事件的命名约定:带有事态的动词或者动词短语
9.事件与委托的关系:
1.事件的声明只是看起来像在声明委托字段
但是中心其实在前面;
而且原型是这样的,事件和委托不可以划等号,事件只是封装了委托
2.为什么要使用委托类型来声明事件?
3.对比事件与属性