c#的serialPort控件有个DataReceived事件,用来响应串口接收到发送来的数据。在做LIS接口的时候,本着”高内聚、低耦合“的原则,我继承了这个控件,并且重新定义了两个事件ResultReceived和QueryReceived,用来响应LIS接口收到结果和收到条码请求两个事件。为了实现上述的功能,就需要了解自定义事件怎么做?
为了了解这个问题,我们追踪一下源代码,发现DataReceived事件代码如下:
public event SerialDataReceivedEventHandler DataReceived;
这其实是一个叫SerialDataReceivedEventHandler的事件,而继续追踪之则有:
public delegate void SerialDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e);
原来定义的这个玩意儿是个委托。看到这里,似乎有恍然大悟的感觉,但是我们觉得有必要再深究一下:
1、为什么要用委托?
为什么要用委托,其实一开始就说明了,委托可以实现各个模块的”高内聚、低耦合“。在异步编程中,如果你想要让各个模块结合的更加松散一点,就必须要用到委托。
这么说好像是很抽象,打个比方可能就很好理解。假设A,B两个人代表两个模块或者说两个类。A想和B一起去吃饭,但是不知道B什么时候会去吃饭。按照顺序逻辑来编程,要实现这个功能,那么逻辑是:A去B那里,A等待,B去吃饭,A和B一起去吃饭。整个过程就是A在那里一直傻傻的盯着B。因此你会说,这太他妈的傻了,浪费时间和精力啊。解决办法是什么呢?就是B去吃饭的时候,告诉A一下,而这个告诉正是定义的委托。
2、委托和回调函数有什么不同。
看到这里,你会说,瞎扯啥委托啊,搞的这么高深,在C里面这个玩意儿就是回调函数CallBack,例如SetTimer API就可以通过一个callback的函数来调用到时间要执行的程序。
真的是这么简单么,那为什么不直接搞回调函数算了?c#当然有它的高明之处:
1)函数指针只能指向静态函数,是要加static标志的,是只能调用全局函数的。而delegate既可以引用静态函数,又可以引用非静态成员函数。还记得当年我们写callback函数时候只能写成全局函数,因此无法引用类中的变量和方法有多纠结么?如果你不记得可以看看吵吵这篇文章
当初为了将类的实例传递到回调函数中,要么用全局变量,要么你作为参数传递进去!
那是多么痛的过去啊,c#的委托比回调函数强大多了,因为在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。
2)与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。
总而言之,委托比回调,是方便好用,又安全可靠。
3、event这个玩意儿有用么?
讲到这里,你会发现,事件不就是个委托么?那么在写代码的时候,不加event关键词可不可以呢?比如上述的DataReceived去掉event:
public SerialDataReceivedEventHandler DataReceived;
你会发现这样子是可行的,完全木有啥问题,那么加了有啥用呢,加了之后你发现不能serialport.dataReceived=XX,而只能是serialport.dataReceived+=XX了!
换言之,event是更加安全一点的delegate了。
最后,看看怎么自定义事件吧!
1、定义一个委托:
public delegate void ReceiveResultEventHandler(object sender, EventArgs e);
2、在该类中,增加相应的事件
public event ReceiveResultEventHandler ReceiveResult;
3、在激活事件的地方写入代码:
ReceiveResult(this, new EventArgs());
至于事件中的两个参数,我就不再讲了,你可以研究研究!
今天到次为止,明天开始写CS5100的LIS接口协议!
如无特别说明,本博客文章皆为原创。转载请说明,来自吵吵博客。
原文链接:http://chaochaoblog.com/archives/2956
吵吵微信朋友圈,请付款实名加入:
笔砚且勿弃,苏张曾陆沉。
网赚客www.67px.com
在家上网赚钱的方法www.67px.com