100165484.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 245 行 · 第 1/3 页
HTM
245 行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>
16.6.5 远程调用和事件
</title></head>
<body>
<div class="area">
<div class="col1">
<div class="lineBlue">
</div>
<!-- title -->
<div class="arcTitle">
<h1>
<a href="../16">
C#高级编程(第3版)【全文连载】
</a>
</h1>
<div style="text-align: center; font-size: 15px">
<a href="100165484.htm">
16.6.5 远程调用和事件
</a>
</div>
<div style="text-align: center; font-size: 15px">
<a class="url" href="../../default.htm">http://book.csdn.net/</a>
2006-10-13 14:41:00
</div>
<div style="margin: 0px auto; width: 700px; border: solid 1px #0b5f98;">
<div style="float: left; width: 16px; background-color: #0b5f98; color: White; padding: 1px;">
图书导读
</div>
<div style="float: right; width: 670px; text-align: left; line-height: 16pt; padding-left: 2px">
<!--导读-->
<h1 id="divCurrentNode" style="color: #b83507; width: 100%; text-align: left; font-size: 12px; padding-left: 2px">当前章节:<a href='100165484.htm'><font color='red'>16.6.5 远程调用和事件</font></a></h1>
<div id="divRelateNode" style="padding-left: 2px">
<div style='float:left;width:49%'>·<a href='100165481.htm'>16.6.2 驻留应用程序</a></div><div style='float:right;width:49%'>·<a href='100165482.htm'>16.6.3 类、接口和Soapsuds</a></div><div style='float:left;width:49%'>·<a href='100165483.htm'>16.6.4 异步远程调用</a></div><div style='float:right;width:49%'>·<a href='100165485.htm'>16.6.6 调用环境</a></div><div style='float:left;width:49%'>·<a href='100165486.htm'>16.7 小结</a></div><div style='float:right;width:49%'>·<a href='100165487.htm'>17.1 System.Globalization命名空间</a></div></div>
</div>
</div>
</div>
<!-- main -->
<div id="main">
<div id="text"> <link href="css.css" rel="stylesheet" type="text/css" /><h3 style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 0cm; MARGIN-RIGHT: 0cm; FTEL: 8.15pt"><span lang="EN-US">16.6.5 </span><span style="FONT-FAMILY: 黑体">远程调用和事件</span></h3>
<p class="MsoNormal" style="LINE-HEIGHT: 15pt"><span style="FONT-FAMILY: 宋体">使用</span><span lang="EN-US">.NET Remoting</span><span style="FONT-FAMILY: 宋体">,不但客户机可以通过网络调用远程对象上的方法,而且服务器也可以调用客户机中的方法。关于这个方面,从基本的语言特性中已经知道,可以使用的机制是委托和事件。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 15pt"><span style="FONT-FAMILY: 宋体">总的来说,体系结构是比较简单的。服务器有客户机可以调用的远程对象,而客户机有服务器可以调用的远程对象:</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'"> </span></span><span style="FONT-FAMILY: 宋体">服务器中的远程对象必须声明一个带有方法签名的外部函数</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">委托</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">,以便客户机在处理程序中执行这些外部函数。</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'"> </span></span><span style="FONT-FAMILY: 宋体">与处理程序函数一起传递给客户机的参数必须是可编组的。因此,发送给客户机的所有数据必须是串行化的。</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'"> </span></span><span style="FONT-FAMILY: 宋体">远程对象也必须声明一个委托函数的实例,其中的委托函数可以通过</span><span lang="EN-US">event</span><span style="FONT-FAMILY: 宋体">关键字修改。客户机将使用该实例注册处理程序。</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'"> </span></span><span style="FONT-FAMILY: 宋体">客户必须创建一个带有处理程序方法的接收器对象,其中的处理程序方法必须与委托定义的接受器对象有一样的签名。此外,客户必须注册接收器对象,这个接收器对象带有远程对象中的事件。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 15pt"><span style="COLOR: black; FONT-FAMILY: 宋体">为了解释这些内容,下面举一个例子。为了阐明</span><span lang="EN-US" style="COLOR: black">.NET Remoting</span><span style="COLOR: black; FONT-FAMILY: 宋体">事件处理的所有内容,需要创建</span><span lang="EN-US" style="COLOR: black">5</span><span style="COLOR: black; FONT-FAMILY: 宋体">个类:</span><span lang="EN-US">Server</span><span style="FONT-FAMILY: 宋体">、</span><span lang="EN-US">Client</span><span style="FONT-FAMILY: 宋体">、</span><span lang="EN-US">RemoteObject</span><span style="FONT-FAMILY: 宋体">、</span><span lang="EN-US">EventSink</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US">StatusEventArgs</span><span style="FONT-FAMILY: 宋体">,它们的依赖关系如图</span><span lang="EN-US">16-16</span><span style="FONT-FAMILY: 宋体">所示。</span></p>
<p align="center"><span lang="EN-US" style="COLOR: black"><img height="323" src="16/image016.gif" width="299" alt="" /></span></p>
<p style="FTEL: 8.15pt" align="center"><span style="COLOR: black; FONT-FAMILY: 宋体">图</span><span lang="EN-US" style="COLOR: black"> 16-16</span></p>
<p class="MsoNormal"><span lang="EN-US">Server</span><span style="FONT-FAMILY: 宋体">类就像我们已经知道的远程服务器一样,将根据配置文件中的信息创建信道,并且注册远程对象。在远程运行库中,远程对象将在</span><span lang="EN-US">RemoteObject</span><span style="FONT-FAMILY: 宋体">类中执行。远程对象声明委托的参数,并且激发已注册的处理程序函数中的事件。传递给处理程序函数的参数是</span><span lang="EN-US">StatusEventArgs</span><span style="FONT-FAMILY: 宋体">类型。类</span><span lang="EN-US">StatusEventArgs</span><span style="FONT-FAMILY: 宋体">必须是串行化的,以便编组传递给客户。</span></p>
<p class="MsoNormal"><span lang="EN-US">Client</span><span style="FONT-FAMILY: 宋体">类代表客户应用程序。这个类创建</span><span lang="EN-US">EventSink</span><span style="FONT-FAMILY: 宋体">类的一个实例,并且把</span><span lang="EN-US">EventSink</span><span style="FONT-FAMILY: 宋体">类的</span> <span lang="EN-US">StatusHandler()</span><span style="FONT-FAMILY: 宋体">方法注册为远程对象中委托的处理程序。因为</span><span lang="EN-US">RemoteObject</span><span style="FONT-FAMILY: 宋体">类也是通过网络调用的,所以</span><span lang="EN-US">EventSink</span><span style="FONT-FAMILY: 宋体">必须像</span><span lang="EN-US">RemoteObject</span><span style="FONT-FAMILY: 宋体">类一样可以用于远程调用。</span></p>
<h4 style="FTEL: 21.45pt"><span lang="EN-US">1. </span><span style="FONT-FAMILY: 黑体">远程对象</span></h4>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">远程对象类在文件</span><span lang="EN-US">RemoteObject.cs</span><span style="FONT-FAMILY: 宋体">中执行。如以前的示例所示,远程对象类必须是从</span><span lang="EN-US">MarshalByRefObject</span><span style="FONT-FAMILY: 宋体">派生出来的。为了使客户机能够注册从远程对象中调用的事件处理程序,必须使用关键字</span><span lang="EN-US">delegate</span><span style="FONT-FAMILY: 宋体">声明一个外部函数。我们声明的委托</span><span lang="EN-US">StatusEvent()</span><span style="FONT-FAMILY: 宋体">带有两个参数:即</span><span lang="EN-US">sender(</span><span style="FONT-FAMILY: 宋体">使用这个参数,客户机可以确定激发事件的对象</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">和一个</span><span lang="EN-US">StatusEventArgs</span><span style="FONT-FAMILY: 宋体">类型的变量。可以把要发送给客户机的所有附加信息都放到该参数类中。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">要在客户机中执行的方法有一些严格的要求,它只能有输入参数,而不允许有返回类型、</span><span lang="EN-US">ref</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US">out</span><span style="FONT-FAMILY: 宋体">参数;参数类型必须是</span><span lang="EN-US">[Serializable]</span><span style="FONT-FAMILY: 宋体">或可用于远程调用</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">它从</span><span lang="EN-US">Marshal ByRefObject</span><span style="FONT-FAMILY: 宋体">派生出来</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">,使用</span><span lang="EN-US">StatusEvent</span><span style="FONT-FAMILY: 宋体">委托定义的参数可以满足这些要求:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public delegate void StatusEvent(object sender, StatusEventArgs e);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">public class RemoteObject : MarshalByRefObject</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="MsoNormal"><span style="COLOR: black; FONT-FAMILY: 宋体">在类</span><span lang="EN-US" style="COLOR: black">RemoteObject</span><span style="COLOR: black; FONT-FAMILY: 宋体">中,声明</span><span lang="EN-US" style="COLOR: black">StatusEvent</span><span style="COLOR: black; FONT-FAMILY: 宋体">类型的一个事件,该事件是一个委托。客户机必须给</span><span lang="EN-US" style="COLOR: black">Status</span><span style="COLOR: black; FONT-FAMILY: 宋体">事件添加事件处理程序,以便从远程对象中获取状态信息:</span></p>
<p class="a6" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public class RemoteObject : MarshalByRefObject</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> public RemoteObject()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> Console.WriteLine("RemoteObject constructor called");</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US"> public event StatusEvent Status;</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">在</span><span lang="EN-US">LongWorking()</span><span style="FONT-FAMILY: 宋体">方法中,我们检查在使用</span><span lang="EN-US">Status(this, e)</span><span style="FONT-FAMILY: 宋体">激发事件之前事件处理程序是否</span> <span style="FONT-FAMILY: 宋体">已注册。为了验证事件是否异步激发,就在执行</span><span lang="EN-US">Thread.Sleep()</span><span style="FONT-FAMILY: 宋体">之前在方法的开端激发一次事件并在执行之后激发一次事件:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public void LongWorking(int ms)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> Console.WriteLine("RemoteObject: LongWorking() Started");</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> StatusEventArgs e = new StatusEventArgs(</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> "Message for Client: LongWorking() Started");</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> // fire event</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> if (Status != null)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> {</span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?