委托:对方法的绑定
事件和委托的步骤
1.定义委托
public delegate 返回值 委托名(参数);
2.基于委托定义事件
public event 委托名 事件名;
3.注册事件
对象.事件名 += new 委托(方法);
4.触发事件
先检查事件是否有人注册,有则触发
if (事件名 != null)
事件名();
委托:对方法的绑定
事件和委托的步骤
1.定义委托
public delegate 返回值 委托名(参数);
2.基于委托定义事件
public event 委托名 事件名;3.注册事件
对象.事件名 += new 委托(方法);4.触发事件
先检查事件是否有人注册,有则触发
if (事件名 != null)
事件名();转载于:https://www.cnblogs.com/liuyudun/p/3812732.html
相信大家在面试的时候会经常问到事件和委托的区别,为什么.net中需要事件和委托这样类似的问题吧,对于一些初学者来说可平时用的过程中也不知道为什么, 只知道这样用,而对于其中的实现机制不是很清楚, 所以面试的时候总是感觉回答的不是很有底气的, 对于委托和事件园子里面也有很多人写过这样的文章,比如张子阳博客中C# 中的委托和事件, 这篇文章由浅入深讲解了.net中的事件和委托。所以比较建议初学者看看的,而且很容易懂.(本人第一次写,如果什么地方说错了的地方请大家海涵和及时纠正我)
在张子阳的文章我相信已经把事件和委托讲的很清楚了,下面我说说我感觉需要注意的地方。
为什么会有委托
在C++中用函数指针来实现回调函数(回调函数是一种非常有用的编程机制),然而函数指针不是类型安全的, 所以.net Framework提供了称为委托的类型安全的机制来实现函数的回调。
编译器如何解析委托
当我们像下面一样在代码中定义一个委托时,
Public delegate void Comparator(int value);
但是编译器遇到这行代码会定义一个类:
View Code
1 Public class Comparator:System.MulticastDelegate 2 { 3 public Comparator(Object object, IntPtr method); 4 5 public virtual Void Invoke(Int32 value); 6 7 public virtual IAsyncResult BeginInvoke(Int32 vlaue, AsyncCallback callback, Object object ); 8 9 public virtual void EndInvoke(IAsyncResult result); 10 11 }从上面代码可以知道 委托 也是一个类,其中有一个构造器,Invoke方法,BeginInvoke方法 和EndInvoke方法。构造器有两个参数,对象引用传给构造器的Object参数,方法的引用传给method 参数,对于静态方法,会为Object 参数传递null.
事件
先看一个事件的定义:
//定义事件委托(代理) public delegate void Comparator(int value1,int value2); //定义事件 public event Comparator onComparator;
编译器在编译事件的时候会把它转换为三个构造:
private Comparator onComparator = null; public void add_onComparator(Comparator value) { // 以一种线程安全的方式对事件添加一个委托 } public void remove_onComparator(Comparator value) { // 以一种线程安全的方式对事件移出一个委托 }从上面代码可以看出第一部分是申明一个私有的委托字段, 后面两部分是对这个委托字段的add访问器和remove 访问器,我们知道属性中有get 和set 访问器,其实事件就是委托字段的访问器,只是访问器方法用add 和remove,而属性用get和set.
总结:
到这里我要讲的差不多说完了, 这是我第一次写文章,尽管上面的内容理解的不是很深入,但是我只是想通过这样的方式来巩固自己看到的知识,因为我觉得这样可以记录下我不同时段对知识的理解以及写的时候自己也在不断思考,这样会有利于对知识的理解。
最后我为初学者推荐关于深入理解.net Framework几本书, 因为我感觉很多初学者不知道买什么书来学习。
- CLR via C# (第三版) 作者:Jeffrey Richter (周靖译) 清华大学出版社
- 深入理解C#(第2版)作者:Jon Skeet 周靖(译)人民邮电出版社
现在关于C# 方面的书籍很多,所以对于一些初学者来说不知道怎么选择, 我推荐上面两本书,如果认真的看完的话, 我相信你肯定对.net 会有一定的理解, 然后通过项目实践的方式对书中内容进行巩固。个人觉得要深入理解程序底层的东西, 有必要阅读一些关于操作系统和编译器相关的书籍,本人一向提倡“知其然知其所以然”的学习方式。
在此推荐一本操作系统相关的书籍: 深入理解计算机系统 (美)布莱恩特,奥哈拉伦 著 龚奕利,雷迎春 译 机械工业出版社。
希望这篇文章对大家会有帮助。
作者:Learning hard
出处:http://www.cnblogs.com/zhili/
转载于:https://www.cnblogs.com/zhili/archive/2012/06/25/Dalegate_and_Event.html
前言:作为.Net攻城狮,你面试过程中是否遇到过这样的问题呢:什么是事件?事件和委托的区别?既然事件作为一种特殊的委托,那么它的优势如何体现?诸如此类…你是否也曾经被问到过?你又是否都答出来了呢?
关于面试中涉及到的事件的问题,我们只需要抓住几个关键点就好了:
(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变量eMyStudyEvent里面添加委托和移除委托。当调用事件的+=和-=时,eMyStudyEvent里面就合并和移除传过来的委托,当事件触发的时候,eMyStudyEvent变量就执行。这样设计也正好符合封装的原则,保证了内部变量的安全性。
//私有委托变量 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); }
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变量,除了+=和-=操作,其他所有操作都会报错:
从这里可以看出,事件对委托进行了封装和约束。
总而言之,言而总之,事件和委托,打一个不太恰当的比喻,就类似面包和面粉,面包是由面粉加工而来的,当我们肚子饿了的时候,面包直接就能吃,面粉还需要加工。而当我们需要面条的时候,面粉就派上用场了,面包对于我们来说是用不了的。不知道这样解释好理解否。说了这么多,确实有点绕,需要好好体会下。
转载于:https://www.cnblogs.com/RaindayXia/p/5261797.html
C#中的委托是什么?事件是不是一种委托?事件和委托的关系?
a. 委托 可以把一个方法作为参数代入另一个方法。
b. 委托可以理解为指向一个函数的指针
c. 委托和事件没有可比性,因为委托是类型,事件是对象