前言:作为.Net攻城狮,你面试过程中是否遇到过这样的问题呢:什么是事件?事件和委托的区别?既然事件作为一种特殊的委托,那么它的优势如何体现?诸如此类...你是否也曾经被问到过?你又是否都答出来了呢?上两篇由浅及深介绍了下委托的用法,这篇还是来说说事件。希望通过这篇的介绍,博友能有个系统的认识,至少应付面试没问题了吧。不信?瞧瞧去~~

C#基础系列目录:

  开篇博主也不多说废话了,翠花,上答案。。。关于面试中涉及到的事件的问题,我们只需要抓住几个关键点就好了:

(1)事件是委托的封装,可以理解为一种特殊的委托。

(2)事件里面其实就两个方法(即add_event()和remove_event())和一个私有的委托变量,这两个方法里面分别是对这个私有的委托变量进行的合并和移除,当调用事件的+=时其实是调用的事件里面的add_event()方法,同样-=调用的是remove_event()方法。

(3)事件只能够从对象外部增加新的响应方法和删除已知的响应方法,而不能主动去触发事件和获取其他注册的响应方法等信息。如果使用公有的delegate则不能做这些限制,也就是说事件对委托做了限制,使委托使用起来更加方便。也有人说事件是对委托的阉割,大概也是这个意思。

如果回答的时候抓住了以上的3点,那么我想你的面试应该不会太差。毕竟面试那么短的时间,有一两个亮点就很不错了,你说呢。哪怕你对事件机制完全不懂,为了面试记住其中两点也是很好的,工作经验咱们没有,换工作的经验可不能没有哦~~扯远了,关于面试就到此为止。如果你还想继续将事件了解透彻,别着急,慢慢往下看。

1、事件的定义及由来:

定义事件:

    public delegate void MyStudyEvent(object sender, EventArgs e);
public class TestEvent
{
public event MyStudyEvent eMyStudyEvent;
}

将这段代码生成dll后,通过反编译工具reflector我们可以看到:

正如上文所说,可以看到当定义一个事件public event MyStudyEvent eMyStudyEvent的时候,编译器会自动给他生成两个方法add和remove,以及一个private的委托变量eMyStudyEvent。我们将反编译代码copy出来看看。

     //私有委托变量
private MyStudyEvent eMyStudyEvent; //add方法合并委托到eMyStudyEvent里面
public void add_eMyStudyEvent(MyStudyEvent value)
{
MyStudyEvent event3;
MyStudyEvent eMyStudyEvent = this.eMyStudyEvent;
do
{
event3 = eMyStudyEvent;
MyStudyEvent event4 = (MyStudyEvent)System.Delegate.Combine(event3, value);
eMyStudyEvent = Interlocked.CompareExchange<MyStudyEvent>(ref this.eMyStudyEvent, event4, event3);
}
while (eMyStudyEvent != event3);
} //remove方法移除eMyStudyEvent里面已存在的委托
public void remove_eMyStudyEvent(MyStudyEvent value)
{
MyStudyEvent event3;
MyStudyEvent eMyStudyEvent = this.eMyStudyEvent;
do
{
event3 = eMyStudyEvent;
MyStudyEvent event4 = (MyStudyEvent)System.Delegate.Remove(event3, value);
eMyStudyEvent = Interlocked.CompareExchange<MyStudyEvent>(ref this.eMyStudyEvent, event4, event3);
}
while (eMyStudyEvent != event3);
}

可以看到这两个方法的主要作用就是在向private变量eMyStudyEvent里面添加委托和移除委托。当调用事件的+=和-=时,eMyStudyEvent里面就合并和移除传过来的委托,当事件触发的时候,eMyStudyEvent变量就执行。这样设计也正好符合封装的原则,保证了内部变量的安全性。

2、Framework里面的事件:既然自定义的事件是这样的,那么有人就要问了,.Net里面的事件是否也是如此。我们直接通过反编译工具来看。我们找到System.Windows.Forms下面的Button类,这个也是我们Winform里面使用最多的按钮,我们来看看我们经常使用的事件。

base.DoubleClick转到定义:

Events.AddHandler()转到定义:

是不是很眼熟,也是通过Delegate.Combine()来合并委托。

3、自定义事件的使用。事件使用的例子园子里面文章也很多,此片博主就以监听文件夹里面的1.txt文件是否存在为例说明事件的使用以及使用事件和委托的区别。

首先定义事件以及触发事件的方法:

  

   public delegate void FileWatchEventHandler(object sender, EventArgs e);

    public class FileWatch
{
private bool _bLastStatus = false;
public FileWatch()
{ } public event FileWatchEventHandler FileWatchEvent; protected virtual void OnFileChange(EventArgs e)
{
if (FileWatchEvent != null)
{
FileWatchEvent(this, e);
}
}

     //事件监听的方法
public void MonitorFile()
{
bool bCurrentStatus; while (true)
{
bCurrentStatus = File.Exists(@"C:\Users\user\Desktop\桌面文件夹\1.txt"); if (bCurrentStatus != _bLastStatus)
{
_bLastStatus = bCurrentStatus;
OnFileChange(EventArgs.Empty);
} Thread.Sleep();
} }
}

然后在Main函数里面启动监听以及定义事件处理方法:

     static FileWatch FileWatchEventSource;

        static void Main(string[] args)
{
FileWatchEventSource = new FileWatch();
//1. 启动后台线程添加监视事件
var thrd = new Thread(new ThreadStart(FileWatchEventSource.MonitorFile));
thrd.IsBackground = true;
thrd.Start(); //2.注册本地事件处理方法
FileWatchEventSource.FileWatchEvent += new FileWatchEventHandler(OnFileChange); Console.ReadLine();
} private static void OnFileChange(object Sender, EventArgs e)
{
Console.WriteLine(DateTime.Now.ToString() + ": 文件发生改变.");
}

启动程序后,每当在文件夹里面删除和创建1.txt的时候就会打印提示文件改变。

博主好奇心重,貌似这种监听直接用委托也可以实现了。于是乎将event事件变量直接改成委托变量。

//public event FileWatchEventHandler FileWatchEvent;
public FileWatchEventHandler FileWatchEvent;

然后运行。发现可以得到一样的结果。

只是在反编译的时候没有add和remove方法而已:

这里正是需要说明的上面的面试回答第三条:事件只能通过+=和-+去阉割委托,而不能主动触发事件。如当使用事件的机制public event FileWatchEventHandler FileWatchEvent时。在Main函数里面

static void Main(string[] args)
{
FileWatchEventSource = new FileWatch();
//1. 启动后台线程添加监视事件
var thrd = new Thread(new ThreadStart(FileWatchEventSource.MonitorFile));
thrd.IsBackground = true;
thrd.Start(); //2.注册本地事件处理方法 FileWatchEventSource.FileWatchEvent += new FileWatchEventHandler(OnFileChange);      //这样写是报错的。
FileWatchEventSource.FileWatchEvent(null, null); Console.ReadLine();
}

这样写是会报错的FileWatchEventSource.FileWatchEvent(null, null);因为事件不能主动触发,而改成委托后这样写就是正确的。并且如果是event变量,除了+=和-=操作,其他所有操作都会报错:

从这里可以看出,事件对委托进行了封装和约束。

  总而言之,言而总之,事件和委托,打一个不太恰当的比喻,就类似面包和面粉,面包是由面粉加工而来的,当我们肚子饿了的时候,面包直接就能吃,面粉还需要加工。而当我们需要面条的时候,面粉就派上用场了,面包对于我们来说是用不了的。不知道这样解释好理解否。说了这么多,确实有点绕,需要好好体会下。

C#基础系列——再也不用担心面试官问我“事件”了的更多相关文章

  1. 再也不用担心面试官问你HashCode和equals了

    结论 如果两个对象相等,则hashcode()必须相等. 如果两个对象相等,a.equals(b)==b.equals(a)==true 如果两个对象有相同的hashcode值,他们也不一定是相等的. ...

  2. 保姆级神器 Maven,再也不用担心项目构建搞崩了

    今天来给大家介绍一款项目构建神器--Maven,不仅能帮我们自动化构建,还能够抽象构建过程,提供构建任务实现:它跨平台,对外提供了一致的操作接口,这一切足以使它成为优秀的.流行的构建工具,从此以后,再 ...

  3. 妈妈再也不用担心别人问我是否真正用过redis了

    1. Memcache与Redis的区别 1.1. 存储方式不同 1.2. 数据支持类型 1.3. 使用底层模型不同 2. Redis支持的数据类型 3. Redis的回收策略 4. Redis小命令 ...

  4. 【阿里云产品公测】离线归档OAS,再也不用担心备份空间了

    [阿里云产品公测]离线归档OAS,再也不用担心备份空间了 作者:阿里云用户莫须有3i 1 起步  1.1 初识OAS  啥是OAS,请看官方说明: 引用: 开放归档服务(Open Archive Se ...

  5. 妈妈再也不用担心我使用git了

    妈妈再也不用担心我使用git了 Dec 29, 2014 git git由于其灵活,速度快,离线工作等特点而倍受青睐,下面一步步来总结下git的基本命令和常用操作. 安装msysgit 下载地址:ms ...

  6. 利用CH341A编程器刷新BIOS,恢复BIOS,妈妈再也不用担心BIOS刷坏了

    前几天,修电脑主析就捣鼓刷BIOS,结果刷完黑屏开不了机,立刻意识到完了,BIOS刷错了.就从网上查资料,各种方法试了个遍,什么用处都没有.终于功夫不负有心人,找到了编码器,知道了怎么用.下面看看具体 ...

  7. 教会舍友玩 Git (再也不用担心他的学习)

    舍友长大想当程序员,我和他爷爷奶奶都可高兴了,写他最喜欢的喜之郎牌Git文章,学完以后,再也不用担心舍友的学习了(狗头)哪里不会写哪里 ~~~ 一 先来聊一聊 太多东西属于,总在用,但是一直都没整理的 ...

  8. 锋利的js之妈妈再也不用担心我找错钱了

    用js实现收银功能. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...

  9. 有了 tldr,妈妈再也不用担心我记不住命令了

    引言 有一次我在培训时说「程序员要善于使用 Terminal 以提高开发效率」,一位程序员反驳道:「这是 21 世纪,我们为什么要用落后的命令行,而不是先进的 GUI?」 是的,在一些人眼里,这个黑黑 ...

随机推荐

  1. 美女jquery图片播放器插件

    相册在线查看http://keleyi.com/keleyi/phtml/image/6.htm 可全屏,可拖动,可自动播放的jquery图片展示插件 使用说明:1.引用css文件:<link ...

  2. CSS3D效果

    效果如本博客中右边呢个浅色框框,来自webpack首页(IE绕路0_0) github地址:http://wjf444128852.github.io/demo02/css3/css3d/ 思路: 1 ...

  3. js 数组去重(7种)

    第一次写技术博客,之前总是认为写这些会很浪费时间,还不如多看几篇技术博文.但...但昨天不知道受了什么刺激,好像有什么在驱使着自己要写一样,所以才有了今天的第一篇博文.总觉得应该要坚持这样写下去.初次 ...

  4. React入门最好的学习实例-TodoList

    前言 React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件. 最近前端界闹的沸沸扬扬的技术当属react了,加上项目需要等等原因,自己也决定花些时间来好 ...

  5. JavaScript区分click事件和mousedown(mouseup、mousemove)方法

    在前端开发工作中,会遇到这样问题:针对同一个dom元素,即希望为它绑定click事件,又想该元素可以允许拖拽的效果.而使用拖拽的效果,我们一般就会用到mousedown,mousemove和mouse ...

  6. SharePoint 2013 入门教程之创建页面布局及页面

    在SharePoint的使用过程中,页面布局和页面时很重要的两个概念,主要用于数据个性化展示,下面,我们简单介绍一下SharePoint的页面布局和页面的个性化. 一. SharePoint页面模型概 ...

  7. MyEclipse使用心得:SVN插件安装方法

    1.在线安装,打开myeclipse,help--->MyEclipse Configuration Center 2.点击Add Site 打开对话框,在对话框Name输入Svn,URL中输入 ...

  8. 生成的API分析文件太大。我们无法在交付前验证您的API使用信息。这只是通知信息。

    这次使用了APICloud平台来开发移动APP, 发布的时候在api控制台云编译成ipa后,这次使用apple提供的Application Loader工具提交apa文件到iTunes上去,提交结束的 ...

  9. 【代码笔记】iOS-获得设备型号

    一,代码. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. ...

  10. 如何在 ASP.NET 4.6 与 IIS10 中运用 HTTP/2 ?

    在过去十年中,Web 技术已经取得了种种进展.从基本的 HTML 开始,网页发展出更丰富的外观和感觉,变得更加直观,对用户更加友好并且越来越大放异彩.这些变化的关键贡献来自于一些新的和翻新技术,且借力 ...