c#中的委托、事件、Func、Predicate、Observer设计模式以及其他

参考资料:

1. 简单谈谈事件与委托

2. C#中的委托和事件(上)

3. C#中的委托和事件(下)

4. delegate,event, lambda,Func,Action以及Predicate

5. 事件与委 托有别, delegate 与 Delegate 相异

6. C# events vs. delegates

7. Delegate,Action,Func, 匿名方法,匿名委托,事件

8. Difference between events and delegates and its respective applications

 

事件的一个综合性的例子:MSDN中BackgroundWorker 类示例

 

说明:
由于本文内容比较杂,前边的叙述部分只是破碎条目的聚合,没有逻辑连贯性。请仔细阅读最后的observer设计模式范例的注释,一切尽在注释中了。

 

  委托
委托保持方法的引用

只有与某委托具有相同签名的方法才能被该委托引用。

 

委托示例一:

匿名委托的常见例子:
this.button1.Click += new EventHandler(button1_Click);

但有时候我们也可以匿名地写成这样:

this.button1.Click += button1_Click;

 

委托的一些总结:
使用+=进行绑定之前必须先使用=给委托赋值,否则会出现“使用了未赋值的局部变量”的编译错误。"

可以将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其绑定的方法。

不管之前这个委托绑定了多少函数,只要一进行赋值,原来绑定的和赋值的方法都被冲掉了。

在委托被赋值(值为某个函数名)之后,程序中凡是该函数名出现的地方,都可以用这个委托代替。

委托示例二:

 

事件
用C语言写一个“事件”的模拟程序
Example.c

 

事件只能用 "+=" 或"-=", 这有效地防止了在委托已被其他函数绑定时由于误用=而导致的委托调用链被清空。

 

event前边的访问修饰符只决定谁能够注册(或说监听)它,并不决定谁能够调用它。就调用来说,无论event声明时有没有public关键字,事件本身都会被编译成private,然后编译器会编译出来两个方法,分别是add和remove,当你用"+="对事件进行绑定时,其实编译器是在调用add方法。而add方法和remove方法的访问限制是由声明事件时候的访问限制符决定的。

 

因此永远只有声明它的那个类可以调用它,其他类与事件的交互只能通过"+="和"-="。这意味着即使它的子类也不能通过直接调用的方式触发事件。为了使其他类能够触发这个事件,我们可以在声明该事件的类中加一触发该事件的公开方法。当然,如果你希望子类能够重写触发的过程,那么你完全可以把这个公开的方法搞成virtual的。

而普通的委托(delegate)相当于一个字段,声明时候的访问限制符完全决定了委托的访问限制属性。

此处比较拗口,请阅读observer模式范例中的注释。

 

  委托与事件的区别
1. 事件可以被包含在接口的声明中,字段不可以.

 

例子:


2.

Events are marked as such in the metadata. This allows things like the Windows Forms or ASP.NET designers to distinguish events from mere properties of delegate type, and provide appropriate support for them (specifically showing them on the Events tab of the Properties window).


3.

习惯上:

委托在功能上常被用作“函数指针”,常作为某函数的输入。

事件在功能上常被用于:订阅消息。

 

delegate和Delegate的差别
 

而Delegate 是  System.MulticastDelegate 的父类。

delegate 仅仅是 C# 的关键字,表示一个继承自 System.MulticastDelegate 的具体委托类

Delegate 和  System.MulticastDelegate 都是抽象类,只有编译器才可以从此类派生。也就是说,除了用 delegate 这种形式,我们不能显式地从Delegate和System.MulticastDelegate这两个类派生。

 

 

匿名方法与Labmda表达式
 

例子:

  

 

 

Lambda表达式可以添加多行语句

(Str1, str2)=>{ 

        Console.WriteLine("哈哈~"); 

        Return str.EndsWith(str2);

Lambda表达式若没有参数,则可以用一个空括号来代替。

 

 

 

Action和Func和Predicate
 

Action、Func、Predicate本质上都是委托

 

Action是无返回值的泛型委托

Action 表示无参,无返回值的委托

Action<int,string> 表示有传入参数int,string无返回值的委托

 

Func是有返回值的泛型委托

Func<int> 表示无参,返回值为int的委托

Func<object,string,int> 表示传入参数为object, string 返回值为int的委托

 

Predicate 是返回bool型的谓语泛型委托

Predicate<int> 表示传入参数为int 返回bool的委托

 

Action示例:

 

 

 

Func示例:

 

Observer设计模式
Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。

Observer模式主要包括如下两类对象:

 

Subject:被监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个被监视对象,它的temprature字段就是其他对象感兴趣的内容,当这个字段的值大于95时时,会不断把数据发给监视它的对象。

Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

假设热水器由三部分组成:heater(热水器)、alarm(警报器)、display(显示器),它们来自于不同厂商并进行了组装。那么,应该是heater仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由alarm发出警报、display显示水温。

怎么实现“水烧开时,heater通知alarm和display”呢。我们通过“事件”来实现。

 

范例:

 

 

但这个范例不符合.net framework规范。符合.net规范的应该是

委托类型的名称都应该以EventHandler结束。委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型(代表了产生该事件的那个对象的引用),一个 EventArgs类型(事件产生时候传递的参数)。

 

这些不仅仅是为了编码规范,也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端 (警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了,也就不用在参数e中传递过多的信息了。

符合.net规范的observer模式范例:
 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生命密码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值