在“C#基础之事件(1)”中已对事件有了一个大概,这里对事件进行更深入的学习。

本节按以下内容展开:

1.事件拥有者与事件响应者的关系;

2.事件订阅的多种写法;

3.事件的订阅和取消订阅;

4.多事件返回值的获取;

1.事件拥有者与事件响应者的关系

以下按照最常见到最不常见的关系列出来,并用示例展示:

结合这四副图,分析下内存关系。所谓“XX者"就是指一个对象,就是new class(),对象所包含的事件、事件处理方法都是对象的成员。有了这个认识,在此用A图,这个最常用的关系来写一段“伪代码”。

public class 拥有者类
{
public event 事件类型 事件成员变量; public void 某个方法(参数)
{
。。。
事件成员变量(参数);//此处是调用事件处理方法
。。。
}
} public class 响应者类
{
private 拥有者类 _拥有者对象; public 响应者类(拥有者类 拥有者对象)
{
this._拥有者对象=拥有者对象;
_拥有者对象.事件成员变量+=事件处理方法;
} public string 事件处理方法(参数)
{
。。。
}
}

由上面代码可知,响应者中包含拥有者时,可以通过构造方法传参形式包含进去,实际应用中不限于这种形式,还可以是new 一个拥有者对象、静态类等方式,只要是能包含进去的都是可行的。其它几个关系就更简单了。这些关系搞清楚了,才能“下笔如有神”。

下面是一个实际代码示例(网络资源非原创):

从program类中可以看到,通过调用事件拥有者dg的OnAlarm方法触发了事件,最终是调用了响应者host类的catch方法,与上图中的A的关系模型一样。

class Program
{
static void Main(string[] args)
{
Dog dg = new Dog();
Host ht = new Host(dg);
DateTime now = new DateTime(, , , , , );
DateTime end = new DateTime(, , , , , );
Console.WriteLine("时间快接近深夜0时~~~~");
while (now < end)
{
Console.WriteLine(now);
Thread.Sleep();
now = now.AddSeconds();
}
//午夜零点小偷到达,看门狗引发Alarm事件
Console.WriteLine("月黑风高的午夜: " + now);
Console.WriteLine("小偷悄悄地摸进了主人的屋内... ");
//自定义参数
UserEventArgs e = new UserEventArgs();
dg.OnAlarm(e);
Console.WriteLine("请按任何键退出~");
Console.ReadKey();
}
} //自定一个事件参数类
class UserEventArgs : EventArgs
{
private int iEventArgs;
public int Args
{
set { iEventArgs = value; }
get { return iEventArgs; }
}
public UserEventArgs(int e)
{
iEventArgs = e;
}
} class Dog
{
//1.声明关于事件的委托;
public delegate void AlarmEventHandler(object sender, UserEventArgs e);
//2.声明事件
public event AlarmEventHandler Alarm;
//3.编写引发事件的函数;
public void OnAlarm(UserEventArgs e)
{
if (Alarm != null)
{
for (int k = ; k < e.Args; k++)
{
Console.WriteLine("汪汪~~");
}
Alarm(this, e);
}
}
}
class Host
{
//主人接收到信息引发的动作
public void Catch(object sender, UserEventArgs e)
{
Console.WriteLine("NND小偷,别跑~");
}
public Host(Dog d)
{
d.Alarm += new Dog.AlarmEventHandler(Catch);
}
}

2.事件订阅的多种写法

在“C#基础之事件(1)”中,用

_A.GetStr += OnGetStr;

来订阅事件,但在上例中用

d.Alarm += new Dog.AlarmEventHandler(Catch);

这种形式来订阅,这两种有什么不同吗?,答案是:没有。前一种是C#2.0的方法,也是我们现在常用的方法;后一种是C#1.0的方法。大致在网络上查找了下,绝大部分示例都是用的后一种写法。在实际项目代码中,用的多的还是前一种写法,毕竟更简洁,看起来也舒服。

从后一种写法可知,其本质是new 了一个委托,并把方法当作委托的参数,参见前面“委托”章节,委托有多种写法,那么当然,除上面两种写法外,事件的订阅就同样有多种简略写法,这时的事件处理逻辑就可以直接写在{}中,而不用单独写成一个方法,实际用哪种方法看个人编码习惯和团队规范要求。现展示如下:

lambda表达式写法
Button1.Click+=(s,e)=>{ }; delegate写法
Button1.Click+=delegate(object sender,EventArgs e) { }; 匿名事件处理
Button1.Click+=delegate { };

3.事件的订阅和取消订阅

事件的订阅用“+=”,取消订阅用“-=”,实际是调用了Add和remove的两个方法,想了解详情请参考《CLR via C#》,这里只从应用角度来说明。需要强调一点:如果是在非构造方法中订阅的事件,在适当的时候需取消订阅事件,如果没有取消当再次调用事件订阅时,会第二次订阅同一事件,这样事件处理方法就会执行第二次,如果执行n 次就会触发n次事件处理方法。

4.多事件返回值的获取

多事件返回值可以通过GetInvocationList方法获取,这个在实际中应用中不是很多,但有应用到。以下从网上找了个示例:

 private void button1_Click(object sender, EventArgs e)
{
int Number = ;
Publishser pub = new Publishser();
Subscriber1 sub1 = new Subscriber1();
Subscriber2 sub2 = new Subscriber2();
Subscriber3 sub3=new Subscriber3();
pub.NumberChanged += sub1.OnNumberChanged;
pub.NumberChanged += sub2.OnNumberChanged;
pub.NumberChanged += sub3.OnNumberChanged;
pub.DoComething(Number);
} class Publishser
{
public delegate int DemoEventHandler(int num);
public event DemoEventHandler NumberChanged;
public void DoComething(int temp)
{
if (NumberChanged != null)
{
Delegate[] delArray = NumberChanged.GetInvocationList();
foreach (Delegate del in delArray)
{
DemoEventHandler method = (DemoEventHandler)del;
temp = method(temp);
}
}
MessageBox.Show(temp.ToString());
}
} class Subscriber1
{
public int OnNumberChanged(int num)
{
MessageBox.Show("调用了Subscriber1类,num值为:"+ num);
return num + ; ;
}
} class Subscriber2
{
public int OnNumberChanged(int num)
{
MessageBox.Show("调用了Subscriber2类 num值为:"+num);
return num+;
}
} class Subscriber3
{
public int OnNumberChanged(int num)
{
MessageBox.Show("调用了Subcriber3类,num值为:"+num);
return num+;
}
} 运行得到的结果是: 调用了Subscriber1类,num值为: 调用了Subscriber2类,num值为: 调用了Subscriber3类,num值为:

总结:事件的应用非常广泛,需作为重点来学习。

C#基础之事件(2)的更多相关文章

  1. [.net 面向对象编程基础] (22) 事件

    [.net 面向对象编程基础] (22)  事件 事件(Event)是学习.net面向对象编程很重要的一部分,在学习事件之前,我们实际上已经在很多地方使用了事件,比如控件的click事件等,这些都是. ...

  2. SQL Server 扩展事件(Extented Events)从入门到进阶(2)——在GUI中创建基础扩展事件

    本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟 ...

  3. jQuery基础之事件

    jQuery基础之事件方法,如下图: 代码实现: <script src="JS/jquery-1.12.4.min.js"></script> <s ...

  4. JS 的事件基础、事件侦听与抛发、

    前言 JavaScript是一种事件驱动型语言.事件驱动是指JavaScript引擎并不是在看到代码之后就会立即执行,而是会在合适的时间才去执行.这个合适的时间是指当某个事件发生之后(例如一个输入框的 ...

  5. JavaScript基础—dom,事件

    Js基础-DOM 1:dom:文档对象模型 Dom就是html页面的模型,将每个标签都作为一个对象,js通过调用dom中的属性,方法就可以对网页中的文本框,层等元素进行编程控制.Dom就是一些让jav ...

  6. 【JS】395-重温基础:事件

    本文是 重温基础 系列文章的第二十篇. 这是第三个基础系列的第一篇,欢迎持续关注呀!重温基础 系列的[初级]和[中级]的文章,已经统一整理到我的[Cute-JavaScript](http://js. ...

  7. NodeJS3-3基础API----event(事件触发器)

    1.基础(on) // 如果像对象享有事件能力就要集成EventEmitter const EventEmitter = require('events') //集成EventEmitter类 cla ...

  8. Delphi - 鼠标上下滚动基础消息事件

    Delphi实现对鼠标上下滚动基础消息的截获并处理 前几天有客户提出需求:由于个人PC界面限制,有时候电子图档显示不全,希望通过鼠标上下滚动用来控制电子图档的放大和缩小. 下面通过一个测试Demo来说 ...

  9. IOS开发UI基础UIControl事件

    UIControl事件1.UIControlEventTouchDown单点触摸按下事件:用户点触屏幕,或者又有新手指落下的时候. 2.UIControlEventTouchDownRepeat多点触 ...

随机推荐

  1. Shell入门01-bash Shell特性

    命令和文件自动补齐 [root@hadoop04 ~]# yum -y install bash-completion 命令历史记忆功能 1.上下键 查看历史命令 2.!number 执行histor ...

  2. 漫谈LiteOS之开发板-串口(基于GD32450i-EVAL)

    [摘要] ​主要讲解物联网的技术积累,本期我们先带领大家学习漫谈LiteOS之漫谈开发板第一集-串口,本文基于GD32450i-EVAL对串口以及其通信做了一个简要的分析,以及开发过程中遇到的一些技术 ...

  3. Forrester:华为云容器是容器混合云最佳选择

    近日,国际权威咨询机构Forrester发布<The Forrester New WaveTM: Public Cloud Enterprise Container Platforms, Q3 ...

  4. 为什么QQ能帮你找到失散多年的兄弟?----图论

    编程三分钟的第 44 篇原创文章 为什么qq里"可能认识的人"功能推荐的如此精准? 为什么两个没有什么联系的朋友会相互认识? 一切的背后到底是道德的沦丧,还是人性的扭曲 ? 让我们 ...

  5. 在 Xcode9 中自定义文件头部注释和其他文本宏

    在 Xcode9 中自定义文件头部注释和其他文本宏 . 参考链接 注意生成的plist文件的名称为IDETemplateMacros.plist 在plist文件里设置自己想要的模板 注意plist存 ...

  6. .net core 3.1简体中文语言包,英文只能提示变成中文!

    .net core 3.1简体中文语言包,英文只能提示变成中文!这个是我自己手动用谷歌翻译翻译的一批文档,已经把.net core3.1完全翻译了,由于是翻译器翻译,所以怕翻译有错漏,所以没有去掉英文 ...

  7. 什么是RESTful?RESTfule风格

    导读 理解什么是REST之前,先去脑补以下什么是HTTP,参考[Http协议] 什么是REST? REST(英文:Representational State Transfer,简称REST,意思:表 ...

  8. USB摄像头之130w像素 OV9655配置,ov9650,ov7725,ov7670

    USB摄像头之130w像素 OV9655配置 为了usb2.0采集达到足够的速率,不得不将采用raw格式输出. // 20150411 XVGA 1280*1024 实际上位机需要2560*1024 ...

  9. 基于 asm 实现比 spring BeanUtils 性能更好的属性拷贝框架

    Bean-Mapping 日常开发中经常需要将一个对象的属性,赋值到另一个对象中. 常见的工具有很多,但都多少不够简洁,要么不够强大. 我们经常使用的 Spring BeanUtils 性能较好,但是 ...

  10. 面试题:4个zookeeper的应用场景,你知道几个?

    前言 现在聊的 topic 是分布式系统,面试官跟你聊完了 dubbo 相关的一些问题之后,已经确认你对分布式服务框架/RPC框架基本都有一些认知了.那么他可能开始要跟你聊分布式相关的其它问题了. 分 ...