C#事件由浅至深简析_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > C#事件由浅至深简析

C#事件由浅至深简析

 2014/3/24 17:50:08  hailants  博客园  我要评论(0)
  • 摘要:0.简述C#中的事件可以说是应用相当多的一种机制,这里从浅至深了解下C#中的事件机制:事件的简单应用自定义事件C#事件机制使用事件不得不注意的事PS:公司上网机上没有IDE工具,所以,有些代码只能是简单写一下,无法给出运行截图和完整测测试项目了;大家见谅!另,始终不习惯博客园的排版....1.事件的简单应用在VS的IDE中最简单的事件应用莫过于如下:创建一个WINFORM项目从工具栏中拖一个"按钮"控件到form1界面上,双击按钮控件,VS会自动创建按钮单击事件回调函数
  • 标签:事件 C#

0.简述

  C#中的事件可以说是应用相当多的一种机制,这里从浅至深了解下C#中的事件机制:

    1. 事件的简单应用
    2. 自定义事件
    3. C#事件机制
    4. 使用事件不得不注意的事

  PS公司上网机上没有IDE工具,所以,有些代码只能是简单写一下,无法给出运行截图和完整测测试项目了;大家见谅!另,始终不习惯博客园的排版....

1.事件的简单应用

  在VS的IDE中最简单的事件应用莫过于如下:

    1. 创建一个WINFORM项目
    2. 从工具栏中拖一个"按钮"控件到form1界面上,
    3. 双击按钮控件,VS会自动创建按钮单击事件回调函数,并将函数与按钮单击事件关联,并跳转到事件回调函数button1_Click的代码编辑界面。
    4. 在button1_Click函数中,填写以下代码:
      MessageBox.Show("Hello,这是事件回调结果!");
    5. 按F5看看运行效果吧,点击按钮,弹出什么了?对的,是一个对话框:

        Hello,这是事件回调结果!

  这是最简单的事件应用。接下来让我们看看用代码如何应用事件:

    1. 还是刚才那个按钮,让我们按F7切换到代码编辑界面吧。
    2. 在Form1的构造函数中,InitializeComponent();这一句下面添加我们的事件代码,使得整个构造函数是下面的样子:
      public Form1()
      {
          InitializeComponent();
          button1.MouseHove+=new EventHandler(Button1_MouseHover)
      }
    3. 哦,感谢微软的工程师们,在编写上面代码过程中,IDE会自动生成最终的事件回调函数,我们只需要填写函数内容即可:
      private void Button1_MouseHover(object sender,EventArgs e)
      {
              MessageBox.Show("喂,怎么还不点我?");
      }
    4. 按F5看看运行效果吧。

2.自定义事件

  如何在自定义的类中定义事件呢?参看下面的代码:

class="code_img_closed" src="/Upload/Images/2014032417/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('9f8dc016-3a54-4f8a-856a-53fcddc6b8d7',event)" src="/Upload/Images/2014032417/2B1B950FA3DF188F.gif" alt="" />
public class UserEventClass

{

         public void TriggerEvent()

{

}

protected virtual void OnEventTrigger()

{

         var handler= EventTriggered;

         if(handler!=null)

{

         handler(this,new EventArgs());

}

}

public event EventHandler EventTriggered;

}
View Code

  PS:上面的代码效果是什么呢?调用UserEventClass 实例的TriggerEvent方法即会触发该实例的EventTriggered事件。至于为什么使用OnEventTrigger来最终完成事件的触发,会在下面做出解释。

  然后就可以象使用控件中的事件一样来使用我们自定义的事件了。

  当然,更复杂的自定义事件方式可以在博客园找到很多资料,基本上都大同小异,例如:

C#事件(event)解析-徐洪军

  C#事件-张雪飞

  在上面的文章2中有讲解如何安全引发事件,这就是上面自定义事件代码中使用OnEventTrigger来最终完成事件的触发的原因。同时,OnEventTrigger被标为protected virtual,这样在UserEventClass的子类中,可以重写OnEventTrigger方法来进行需要的修改。

3.C#事件机制

  所有的教材里面都会先讲解C#委托,然后才会讲解C#事件,因为事件本质上仍然是由委托完成的,其神奇的表现仅仅是微软工程师们给我们的语法糖(PS:可能有点偏激)。委托与事件之间的关联可以参看下面的文章:

C# 中的委托和事件-张子阳

C#中的委托和事件(续) -张子阳

  这里面要深究的其实应该是多播委托的委托链调用机制,拿出我们的反编译神器Reflecter,看看Combine里面有什么?

    1. Delegate.Combine里面调用了参数1的Delegate. CombineImpl方法,这一方法在普通的Delegate类中会抛出异常,而MulticastDelegate类重写了该方法。对该方法进行分析可以得出:将本实例及传入的实例这两个MulticastDelegate中的_invocationList列表组合,并以组合出的新列表创建一个新的MulticastDelegate返回。因此Combine返回的将是一个新的MulticastDelegate。_invocationList是一个List<Object>,这一点稍微有点奇怪,而且MulticastDelegate还提供了一个GetInvocationList方法返回Delegate数组,感觉有点多次一举,还得装箱拆箱。
    2. EventHandler继承自MulticastDelegate,并实现了Invoke,BeginInvoke等方法,但是很遗憾,方法内容都是CLR内部调用了,无法探究,但是从MulticastDelegate的构成大略可以猜测出,是遍历_invocationList,并逐个调用每个实例的Delegate.Invoke方法。

4.使用事件不得不注意的事

  上面粗略描述了事件的使用,自定义及其深入机制,下面说说使用事件时需要注意的几个问题:

    1. 都碰到过”线程间操作无效”的异常吧,没错,即便在事件中改变界面控件的属性,调用方法等,也会碰到这个提示,但是有人会说,我在按钮事件中去改变lable的值,为什么没有异常呢?OK,还是委托的机制,委托其实是方法指针,调用委托就意味着委托的实际方法体运行在调用方一致的线程中,UI控件运行在什么线程下呢?界面线程,所以UI事件间进行操作是不会报异常的。如果你用一个SOCKET,如TCPClient,响应接受到数据的事件的话,那么这个事件将不会运行在界面主线程下,于是你就会看到”线程间操作无效”。
    2. 如果事件回调中有一个长时间执行的代码会如何呢?在按钮事件回调里写过数据库操作的人都有同感:卡……。这意味着事件是同步回调而不是异步回调,所以,把你的代码移开吧,并且仔细检查你的代码,保证回调函数中没有诸如死循环之类的……
    3. 如果关联了多个事件回调,那么他们的执行有顺序么?按照官方说法:不保证回调依照绑定顺序调用。不过实际经验来说大多数是和绑定顺序相同的,同时,一个阻塞了,后面的都不会执行;一个回调异常将影响所有回调。
发表评论
用户名: 匿名