分享
 
 
 

《展现C#》第九章 配置和调度

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

第九章 配置和调度

在上一章,你学到如何创建一个通用语言运行时(CLR)组件,且如何在一个简单的测试应用程序中使用它。虽然CLR组件就要准备装载了,但你还是应该思考以下技术之一:

条件编译

文档注释

代码版本化

9.1 条件编译

没有代码的条件编译功能,我就不能继续工作。条件编译允许执行或包括基于某些条件的代码;例如,生成应用程序的一个查错(DEBUG)版本、演示(DEMO)版本或零售(RELEASE)版本。可能被包括或被执行的代码的例子为许可证代码、 屏幕保护或你出示的任何程序。

在C#中,有两种进行条件编译的方法:

预处理用法

条件属性

9.1.1 预处理用法

在C++中,在编译器开始编译代码之前,预处理步骤是分开的。在C#中,预处理被编译器自己模拟—— 没有分离的预处理。它只不过是条件编译。

尽管C#编译器不支持宏,但它具有必需的功能,依据符号定义的条件,排除和包括代码。以下小节介绍了在C#中受支持的各种标志,它们与在C++中看到的相似。

定义符号

依据符号排除代码

引起错误和警告

9.1.1.1 定义符号

你不能使用随C#编译器一起的预处理创建“define 标志:符号:定义 ”宏,但是,你仍可以定义符号。根据某些符号是否被定义,可以排除或包括代码。

第一种定义符号的办法是在C#源文件中使用 #define标志:

#define DEBUG

这样定义了符号DEBUG,且范围在它所定义的文件内。请注意,必须要先定义符号才能使用其它语句。例如,以下代码段是不正确的:

using System;

#define DEBUG

编译器将标记上述代码为错误。你也可以使用编译器定义符号(用于所有的文件):

csc /define:DEBUG mysymbols.cs

如果你想用编译器定义多种符号,只需用分号隔开它们:

csc /define:RELEASE;DEMOVERSION mysymbols.cs

在C#源文件中,对这两种符号的定义分为两行 #define 标志。

有时,你可能想要取消源文件中(例如,较大项目的源文件)的某种符号。可以用 #undef 标志取消定义:

#undef DEBUG

#define的“定义标志:符号: 定义”规则同样适用于#undef: 它的范围在自己定义的文件之内,要放在任何语句如using语句之前。

这就是全部有关用C#预处理定义符号和取消定义符号所要了解的知识。以下小节说明如何使用符号有条件地编译代码。

9.1.1.2 依据符号包括和排除代码

最重要的“if标志:符号:包括代码”方式的目的为,依据符号是否被定义,有条件地包括和排除代码。清单9.1 包含了已出现过的源码,但这次它依据符号被有条件地编译。

清单 9.1 利用 #if 标志有条件地包括代码

1: using System;

2:

3: public class SquareSample

4: {

5: public void CalcSquare(int nSideLength, out int nSquared)

6: {

7: nSquared = nSideLength * nSideLength;

8: }

9:

10: public int CalcSquare(int nSideLength)

11: {

12: return nSideLength*nSideLength;

13: }

14: }

15:

16: class SquareApp

17: {

18: public static void Main()

19: {

20: SquareSample sq = new SquareSample();

21:

22: int nSquared = 0;

23:

24: #if CALC_W_OUT_PARAM

25: sq.CalcSquare(20, out nSquared);

26: #else

27: nSquared = sq.CalcSquare(15);

28: #endif

29: Console.WriteLine(nSquared.ToString());

30: }

31: }

注意,在这个源文件中没有定义符号。当编译应用程序时,定义(或取消定义)符号:

csc /define:CALC_W_OUT_PARAM square.cs

根据“ if标志:符号:包括代码”的符号定义,不同的 CalcSquare 被调用了。用来对符号求值的模拟预处理标志为#if、 #else和 #endif。它们产生的效果就象C#相应的if 语句那样。你也可以使用逻辑“与”(&&)、逻辑“或”(¦¦)以及“否”(!)。它们的例子显示在清单9.2 中。

清单 9.2 使用#elif 在#if标志中创建多个分支

1: // #define DEBUG

2: #define RELEASE

3: #define DEMOVERSION

4:

5: #if DEBUG

6: #undef DEMOVERSION

7: #endif

8:

9: using System;

10:

11: class Demo

12: {

13: public static void Main()

14: {

15: #if DEBUG

16: Console.WriteLine("Debug version");

17: #elif RELEASE && !DEMOVERSION

18: Console.WriteLine("Full release version");

19: #else

20: Console.WriteLine("Demo version");

21: #endif

22: }

23: }

在这个“if标志:符号:包含代码”例子中,所有的符号都在C#源文件中被定义。注意第6行#undef语句增加的那部分。由于不编译DEBUG代码的DEMO版本(任意选择),我确信它不会被某些人无意中定义了,而且总当DEBUG被定义时,就取消DEMO版本的定义。

接着在第15~21行,预处理符号被用来包括各种代码。注意#elif标志的用法,它允许你把多个分支加到#if 标志。该代码运用逻辑操作符“&&”和非操作符“!”。也可能用到逻辑操作符“¦¦”,以及等于和不等于操作符。

9.1.1.3 引起错误并警告

另一种可能的“警告 标志错误 标志”预处理标志的使用,是依据某些符号(或根本不依据,如果你这样决定)引起错误或警告。各自的标志分别为 #warning和#error,而清单9.3 演示了如何在你的代码中使用它们。

清单 9.3 使用预处理标志创建编译警告和错误

1: #define DEBUG

2: #define RELEASE

3: #define DEMOVERSION

4:

5: #if DEMOVERSION && !DEBUG

6: #warning You are building a demo version

7: #endif

8:

9: #if DEBUG && DEMOVERSION

10: #error You cannot build a debug demo version

11: #endif

12:

13: using System;

14:

15: class Demo

16: {

17: public static void Main()

18: {

19: Console.WriteLine("Demo application");

20: }

21: }

在这个例子中,当你生成一个不是DEBUG版本的DEMO版本时,就发出了一个编译警告(第5行~第7行)。当你企图生成一个DEBUG DEMO版本时,就引起了一个错误,它阻止了可执行文件的生成。对比起前面只是取消定义令人讨厌的符号的例子,这些代码告诉你,“警告 标志错误 标志”企图要做的工作被认为是错误的。这肯定是更好的处理办法。

9.1.1.4 条件属性

C++的预处理也许最经常被用来定义宏,宏可以解决一种程序生成时的函数调用,而却不能解决另一种程序生成时的任何问题。这些例子包括 ASSERT和TRACE 宏,当定义了DEBUG符号时,它们对函数调用求值,当生成一个RELEASE版本时,求值没有任何结果。

当了解到宏不被支持时,你也许会猜测,条件功能已经消亡了。幸亏我可以报道,不存在这种情况。你可以利用条件属性,依据某些已定义符号来包括方法。

[conditional("DEBUG")]

public void SomeMethod() { }

仅当符号DEBUG被定义时,这个方法被加到可执行文件。并且调用它,就象

SomeMethod();

当该方法不被包括时,它也被编译器声明。功能基本上和使用C++条件宏相同。

在例子开始之前,我想指出,条件方法必须具有void的返回类型,不允许其它返回类型。然而,你可以传递你想使用的任何参数。

在清单9.4 中的例子演示了如何使用条件属性重新生成具有C++的TRACE宏一样的功能。为简单起见,结果直接输出到屏幕。你也可以根据需要把它定向到任何地方,包括一个文件。

清单 9.4 使用条件属性实现方法

1: #define DEBUG

2:

3: using System;

4:

5: class Info

6: {

7: [conditional("DEBUG")]

8: public static void Trace(string strMessage)

9: {

10: Console.WriteLine(strMessage);

11: }

12:

13: [conditional("DEBUG")]

14: public static void TraceX(string strFormat,params object[] list)

15: {

16: Console.WriteLine(strFormat, list);

17: }

18: }

19:

20: class TestConditional

21: {

22: public static void Main()

23: {

24: Info.Trace("Cool!");

25: Info.TraceX("{0} {1} {2}","C", "U", 2001);

26: }

27: }

在Info类中,有两个静态方法,它们根据DEBUG符号被有条件地编译:Trace,接收一个参数,而TraceX则接收n个参数。Trace的实现直接了当。然而,TraceX实现了一个你从没有见过的关键字:params。

params 关键字允许你指定一个方法参数,它实际上接收了任意数目的参数。其类似C/C++的省略参数。注意,

它必须是方法调用的最后一个参数,而且在参数列表中,你只能使用它一次。毕竟,它们的局限性极其明显。

使用params 关键字的意图就是要拥有一个Trace方法,该方法接收一个格式字符串以及无数个置换对象。幸好,还有一个支持格式字符串和对象数组的 WriteLine方法(第16行)。

这个小程序产生的哪一个输出完全取决于DEBUG是否被定义。当DEBUG符号被定义时,方法都被编译和执行。如果DEBUG不被定义,对Trace和TraceX的调用也随之消失。

条件方法是给应用程序和组件增加条件功能的一个真正强大的手段。用一些技巧,你就可以根据由逻辑“或”(¦¦)以及逻辑“与”(&&)连接起来的多个符号,生成条件方法。然而,对于这些方案,我想给你推荐C#文档。

9.2 在XML中的文档注释

很多程序员根本不喜欢的一项任务就是写作,包括写注释和写文档。然而,有了C#,你就找到改变老习惯的好理由:你可以用代码的注释自动生成文档。

由编译器生成的输出结果是完美的XML。它可以作为组件文档的输入被使用,以及作为显示帮助并揭示组件内部细节的工具。例如, Visual Studio 7 就是这样一种工具。

这一节专门为你说明如何最好地运用C#的文档功能。该例子涉及的范围很广,所以你不能有这样的借口,说它过于复杂,以至很难领会如何加入文档注释。文档是软件极其重要的一部分,特别是要被其他开发者使用的组件的文档。

在以下小节中,文档注解用来说明RequestWebPage 类。我已分别在以下几小节中做出解释:

描述一个成员

添加备注和列表

提供例子

描述参数

描述属性

编译文档

9.2.1 描述一个成员

第一步,为一个成员添加一个简单的描述。你可以用 标签这样做:

/// This is ....

每一个文档注释起始于由三个反斜杠组成的符号“///”。你可以把文档注释放在想要描述的成员之前:

/// Class to tear a Webpage from a Webserver

public class RequestWebPage

使用和

标签,为描述添加段落。用标签引用其它已有了注释的成员。

/// Included in the class

增加一个链接到RequestWebPage类的描述。注意,用于标签的语法是XML语法,这意味着标签大写化的问题,而且标签必须正确地嵌套。

当为一个成员添加文档时,另一个有趣的标签是 。它允许你描述可能使读者非常感兴趣的其它话题。

///

前面的例子告诉读者,他可能也想查阅System.Net 名字空间的文档。你一定要给超出当前范围的项目规定一个完全资格名。

作为许诺,清单9.5 包含 RequestWebPage类中正在工作的文档的所有例子。看一下如何使用标签以及嵌套如何为组件产生文档。

清单 9.5 利用 , , , and 标签描述一个成员

1: using System;

2: using System.Net;

3: using System.IO;

4: using System.Text;

5:

6: /// Class to tear a Webpage from a Webserver

7: public class RequestWebPage

8: {

9: private const int BUFFER_SIZE = 128;

10:

11: /// m_strURL stores the URL of the Webpage

12: private string

[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- 王朝網路 版權所有