程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言基礎知識 >> 第九章 配置和調度

第九章 配置和調度

編輯:C語言基礎知識
第九章  配置和調度

    在上一章,你學到如何創建一個通用語言運行時(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: {
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved