加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

从delegate的Invoke说起

(2015-05-05 18:04:49)
分类: C#拾遗
起因:
在使用serialPort控件进行串口通信的过程中,要将串口接收到的消息显示要UI界面上,结果运行时发生异常,“ 线程间操作无效: 从不是创建控件“textBox”的线程访问它。”。求助度娘,原来从.NET2.0开始,C#默认不允许从不是创建该控件的线程访问该控件,而serialPort控件正是在一个后台线程来接收串口数据。
网上给出的解决方案有两种。第一、可以通过将 CheckForIllegalCrossThreadCalls 属性的值设置为 false 来禁用此异常。这会使控件以与在 Visual Studio 2003 下相同的方式运行。
第二、使用委托,通过Invoke或者BeginInvoke将调用传送到创建此控件的线程。
原来如此,当下定义了一个委托,在serialPort控件的事件处理函数中调用委托的Invoke方法,结果运行时仍然发生异常,让我大失所望。
在此求助于度娘,原来应该使用this.Invoke来调用委托,替换过后,完美运行,问题KO。可是,this.Invoke和委托的Invoke有什么区别呢?
Control.Invoke与delegate的Invoke区别
实际上this.Invoke是类Control的一个方法,Form类继承了Control类,因此可以调用这个方法。在Control.Invoke的MSDN说明中,确实找到这样的解释,Control.Invoke方法在拥有此控件的基础窗口句柄的线程上执行指定的委托。
Control.Invoke的定义如下:public object Invoke(Delegate method, params object[] args);
第一个参数是一个委托,后面的参数是这个委托的参数。当然,Control.Invoke还存在一个委托不带参数的重载函数。
可是,我在查询delegate的Invoke方法的时候让我困惑了,因为Invoke居然不是delegate类的一个方法,一番搜索才发现,这个Invoke还确实不是delegate类的方法,而是由CLR提供的一个方法,MS在这里给了一个简要的说明:Delegate Class
其实不管我们显式的使用delegate的Invoke方法,或者使用委托的实例带参数的形式,CLR都会在运行时调用Invoke方法,delegate的Invoke方法的参数就是delegate绑定的方法的参数。
Control.BeginInvoke与CLR的BeginInvoke
说完Invoke,顺带讲一讲这个BeginInvoke,这两个BeginInvoke的差别跟两个Invoke的差别差不多。Control.BeginInvoke是在控件的创建线程上异步开始调用,CLR的BeginInvoke则是开启一个工作线程进行异步调用,Control.BeginInvoke和CLR的BeginInvoke都会立即返回。
CLR的BeginInvoke的定义为:IAsyncResult delegate.BeginInvoke(Object parameter,AsyncCallback callback, object @object);
callback是异步调用完成后的回调函数的委托,可以在回调函数中调用EndInvoke得到异步调用的结果。需要注意的是在异步调用没有完成的时候,在主线程中调用EndInvoke会导致主线程阻塞,直到异步调用函数执行完成。
总结:
完全可以将Control.Invoke和CLR的Invoke当作是两个不同功能的函数。当需要在工作线程中修改UI控件时,使用Control.Invoke或者Control.BeginInvoke,当需要使用委托来完成异步调用功能时,使用CLR的BeginInvoke。


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有