分享
 
 
 

《展现C#》第八章 用C#写组件

王朝c#·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

第八章 用C#写组件

这一章关于用C#写组件。你学到如何写一个组件,如何编译它,且如何在一个客户程序中使用它。更深入一步是运用名字空间来组织你的应用程序。

这章由两个主要大节构成:

你的第一个组件

使用名字空间工作

8.1 你的第一个组件

到目前为止,在本书中提到的例子都是在同一个应用程序中直接使用一个类。类和它的使用者被包含在同一个执行文件中。现在我们将把类和使用者分离到组件和客户,它们分别位于不同的二进制文件中(可执行文件)。

尽管你仍然为组件创建一个 DLL,但其步骤与用C++写一个COM组件差别很大。你很少涉及到底层结构。以下小节说明了如何构建一个组件以及使用到它的客户:

构建组件

编译组件

创建一个简单的客户应用程序

8.1.1 构建组件

因为我是一个使用范例迷,我决定创建一个相关Web的类,以方便你们使用。它返回一个Web网页并储存在一个字符串变量中,以供后来重用。所有这些编写都参考了.NET框架的帮助文档。

类名为RequestWebPage;它有两个构造函数—— 一个属性和一个方法。属性被命名为URL,且它储存了网页的Web地址,由方法GetContent返回。这个方法为你做了所有的工作(见清单8.1)。

清单 8.1 用于从Web服务器返回HTML网页的RequestWebPage 类

1: using System;

2: using System.Net;

3: using System.IO;

4: using System.Text;

5:

6: public class RequestWebPage

7: {

8: private const int BUFFER_SIZE = 128;

9: private string m_strURL;

10:

11: public RequestWebPage()

12: {

13: }

14:

15: public RequestWebPage(string strURL)

16: {

17: m_strURL = strURL;

18: }

19:

20: public string URL

21: {

22: get { return m_strURL; }

23: set { m_strURL = value; }

24: }

25: public void GetContent(out string strContent)

26: {

27: // 检查 URL

28: if (m_strURL == "")

29: throw new ArgumentException("URL must be provided.");

30:

31: WebRequest theRequest = (WebRequest) WebRequestFactory.Create(m_strURL);

32: WebResponse theResponse = theRequest.GetResponse();

33:

34: // 给回应设置字节缓冲区

35: int BytesRead = 0;

36: Byte[] Buffer = new Byte[BUFFER_SIZE];

37:

38: Stream ResponseStream = theResponse.GetResponseStream();

39: BytesRead = ResponseStream.Read(Buffer, 0, BUFFER_SIZE);

40:

41: //使用 StringBuilder 以加速分配过程

42: StringBuilder strResponse = new StringBuilder("");

43: while (BytesRead != 0 )

44: {

45: strResponse.Append(Encoding.ASCII.GetString(Buffer,0,BytesRead));

46: BytesRead = ResponseStream.Read(Buffer, 0, BUFFER_SIZE);

47: }

48:

49: // 赋给输出参数

50: strContent = strResponse.ToString();

51: }

52: }

本应该利用无参数构造函数完成工作,但我决定在构造函数中初始化URL,这可能会很有用。当后来决定要改变URL时——为了返回第二个网页,例如,通过URL属性的get和set访问标志使它被公开了。

有趣的事始于GetContent方法。首先,代码对URL实行十分简单的检查,如果它不适合,就会引发一个ArgumentException 异常。之后,我请求WebRequestFactory ,以创建一个基于传递给它的URL的WebRequest对象。

因为我不想发送cookies、附加头和询问串等,所以立即访问WebResponse(第32行)。如果你需要请求上述任何的功能,必须在这一行之前实现它们。

第35和36行初始化一个字节缓冲区,它用于从返回流中读数据。暂时忽略StringBuilder 类,只要返回流中仍然有要读的数据,while循环就会简单地重复。最后的读操作将返回零,因此结束了该循环。

现在我想回到StringBuilder类。为什么用这个类的实例而不是简单地把字节缓冲区合并到一个字符串变量?看下面这个例子:

strMyString = strMyString + "some more text";

这里很清楚,你正在拷贝值。常量 "some more text" 以一个字符串变量类型被加框,且根据加法操作创建了一个新的字符串变量。接着被赋给了 strMyString。有很多次拷贝,是吗?但你可能引起争论

strMyString += "some more text";

不要炫耀这种行为。对不起,对于C#这是一个错误的答案。其操作完全与所描述的赋值操作相同。

不涉及该问题的另外的途径是使用StringBuilder类。它利用一个缓冲区进行工作,接着,在没有发生我所描述的拷贝行为的情况下,你进行追加、插入、删除和替换操作。这就是为什么我在类中使用它来合并那些读自缓冲区中的内容。

该缓冲区把我带进了这个类中最后重要的代码片段——第45行的编码转换。它只不过涉及到我获得请求的字符集。

最后,当所有的内容被读入且被转换时,我显式地从 StringBuilder请求一个字符串对象并把它赋给了输出变量。一个返回值仍然会导致另外的拷贝操作。

8.1.2 编译组件

到目前为止,你所做的工作与在正常应用程序的内部编写一个类没有什么区别。所不同的是编译过程。你必须创建一个库而不是一个应用程序:

csc /r:System.Net.dll /t:library /out:wrq.dll webrequest.cs

编译开关/t:library 告诉C#编译,要创建一个库而不是搜寻一个静态 Main方法。同样,因为我正在使用 System.Net名字空间,所以必须引用 (/r:)它的库,这个库就是System.Net.dll。

你的库命名为 wrq.dll,现在它准备用于一个客户应用程序。因为在这章中我仅使用私有组件工作,所以你不必把库拷贝到一个特殊的位置,而是拷贝到客户应用程序目录。

8.1.3 创建一个简单的客户应用程序

当一个组件被写成且被成功地编译时,你所要做的就是在客户应用程序中使用它。我再次创建了一个简单的命令行应用程序,它返回了我维护的一个开发站点的首页(见清单8.2)。

清单 8.2 用 RequestWebPage 类返回一个简单的网页

1: using System;

2:

3: class TestWebReq

4: {

5: public static void Main()

6: {

7: RequestWebPage wrq = new RequestWebPage();

8: wrq.URL = "http://www.alphasierrapapa.com/iisdev/";

9:

10: string strResult;

11: try

12: {

13: wrq.GetContent(out strResult);

14: }

15: catch (Exception e)

16: {

17: Console.WriteLine(e);

18: return;

19: }

20:

21: Console.WriteLine(strResult);

22: }

成员

注意,我已经在一个try catch语句中包含了对 GetContent的调用。其中的一个原因是GetContent可能引发一个 ArgumentException异常。此外,我在组件内部调用的.NET框架类也可以引发异常。因为我不能在类的内部处理这些异常,所以我必须在这里处理它们。

其余的代码只不过是简单的组件使用——调用标准的构造函数,存取一个属性,并执行一个方法。但等一下:你需要注意何时编译应用程序。一定要告诉编译器,让它引用你的新组件库DLL:

csc /r:wrq.dll wrclient.cs

现在万事俱备,你可以测试程序了。输出结果会滚屏,但你可以看到应用程序工作。使用了常规的表达式,你也可以增加代码,以解析返回的HTML,并依据你个人的喜好,提取信息。我预想会使用到这个类新版本的SSL(安全套接字层),用于ASP+网页中的在线信用卡验证。

你可能会注意到,没有特殊的using 语句用于你所创建的库。原因是你在组件的源文件中没有定义名字空间。

8.2 使用名字空间工作

你经常使用到名字空间,例如System 和System.Net。C#利用名字空间来组织程序,而且分层的组织使一个程序的成员传到另一个程序变得更容易。

尽管不强制,但你总要创建名字空间,以清楚地识别应用程序的层次。.NET框架会给出构建这种分层的良好思想。

以下的代码片段显示了在C#原文件中简单的名字空间 My.Test(点号表示一个分层等级)的声明:

namespace My.Test

{

//这里的任何东西属于名字空间

}

当你访问名字空间中的一个成员时,也有必要使用名字空间标识符完全地验证它,或者利用using标志把所有的成员引入到你当前的名字空间。本书前面的例子演示了如何应用这些技术。

在开始使用名字空间之前,只有少数有关存取安全的词。如果你不增加一个特定的存取修饰符,所有的类型将被默认为internal 。当你想从外部访问该类型时,使用 public 。不允许其它的修饰符。

这是关于名字空间充分的理论。让我们继续实现该理论——以下小节说明了当构建组件应用程序时,如何

使用名字空间

在名字空间中包装类

在客户应用程序中使用名字空间

为名字空间增加多个类

8.2.1 在名字空间中包装类

既然你知道了名字空间的理论含义,那么让我们在现实生活中实现它吧。在这个和即将讨论到的例子中,自然选择到的名字空间是Presenting.CSharp。为了不使你厌烦,仅仅是把RequestWebPage包装到Presenting.CSharp中,我决定写一个类,用于 Whois查找(见清单8.3)。

清单 8.3 在名字空间中实现 WhoisLookup类

1: using System;

2: using System.Net.Sockets;

3: using System.IO;

4: using System.Text;

5:

6: namespace Presenting.CSharp

7: {

8: public class WhoisLookup

9: {

10: public static bool Query(string strDomain, out string strWhoisInfo)

11: {

12: const int BUFFER_SIZE = 128;

13:

14: if ("" == strDomain)

15: throw new ArgumentException("You must specify a domain name.");

16:

17: TCPClient tcpc = new TCPClient();

18: strWhoisInfo = "N/A";

19:

20: // 企图连接 whois 服务器

21: if (tcpc.Connect("whois.networksolutions.com", 43) != 0)

22: return false;

23:

24: // 获取流

25: Stream s = tcpc.GetStream();

26:

27: // 发送请求

28: strDomain += "\r\n";

29: Byte[] bDomArr = Encoding.ASCII.GetBytes(strDomain.ToCharArray());

30: s.Write(bDomArr, 0, strDomain.Length);

31:

32: Byte[] Buffer = new Byte[BUFFER_SIZE];

33: StringBuilder strWhoisResponse = new StringBuilder("");

34:

35: int BytesRead = s.Read(Buffer, 0, BUFFER_SIZE);

36: while (BytesRead != 0 )

37: {

38: strWhoisResponse.Append(Encoding.ASCII.GetString(Buffer,0,BytesRead));

39: BytesRead = s.Read(Buffer, 0, BUFFER_SIZE);

40: }

41:

42: tcpc.Close();

43: strWhoisInf

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有