C#基础系列——再也不用担心面试官问我“事件”了

简介:

前言:作为.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(250); } } }
复制代码

然后在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变量,除了+=和-=操作,其他所有操作都会报错:

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

 

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

 






本文转自懒得安分博客园博客,原文链接:http://www.cnblogs.com/landeanfen/p/4721525.html,如需转载请自行联系原作者

目录
相关文章
|
5月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
145 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
5月前
|
算法 C# 数据库
【干货】一份10万字免费的C#/.NET/.NET Core面试宝典
C#/.NET/.NET Core相关技术常见面试题汇总,不仅仅为了面试而学习,更多的是查漏补缺、扩充知识面和大家共同学习进步。该知识库主要由自己平时学习实践总结、网上优秀文章资料收集(这一部分会标注来源)和社区小伙伴提供三部分组成。该份基础面试宝典完全免费,发布两年来收获了广大.NET小伙伴的好评,我会持续更新和改进,欢迎关注我的公众号【追逐时光者】第一时间获取最新更新的面试题内容。
267 1
|
5月前
|
C#
c# Gridview 点击checkbox 触发的事件
c# Gridview 点击checkbox 触发的事件
|
1天前
|
存储 开发框架 .NET
常见20道C#面试的题
常见20道C#面试的题
7 1
|
4月前
|
C#
一文搞懂:一道关于C#linqwhere的面试题
一文搞懂:一道关于C#linqwhere的面试题
36 0
|
1月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
69 7
|
2月前
|
C#
由浅入深理解C#中的事件
由浅入深理解C#中的事件
102 19
|
2月前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。废话不多说,总结一句:事件分发机制很重要。
121 9
|
2月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
45 0
|
2月前
|
存储 算法 安全
C#语言进阶(二)—事件全解
C#语言进阶(二)—事件全解
32 0

相关实验场景

更多