国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

CodeDom:語言的界限在這里消失

2024-07-21 02:29:35
字體:
來源:轉載
供稿:網友


  .net推崇這樣一種思想:相對于框架而言,語言處于從屬、次要的地位。codedom名稱空間中包含的類是這一思想的集中體現。我們可以用codedom構造一個樹或圖,用system.codedom名稱空間的類填充它,完成后,用對應各種.net語言的codeprovider對象將樹結構轉換成該種語言的代碼。要更換一種語言,簡單到只需更換一下最后用到的codeprovider對象。
  
    設想一下,利用這一技術,我們至少能夠:
  
    ·查詢存儲過程的元數據,構造出一個負責參數綁定的類。
  
    ·查詢程序集的manifest,構造出一個對每個函數執行單元測試的類。
  
    ·為開發組用到的每一種語言生成樣板代碼。
  
    ·只需寫一份范例代碼,就可以讓用戶自由選擇他們要查看哪一種語言的版本。
  
    ·自定義模板語法,經解析后生成任意語言的代碼。
  
    ·如果要學習某種不熟悉的語言,可以生成該語言的代碼,然后將它與熟悉的語言比較。 
   
  一、基本操作 
   
  system.codedom名稱空間包含了許多以語言中立的形式描述常見程序結構的對象,每一種語言的細節則由與該種語言對應的codeprovider對象負責處理。例如,codeconditionstatement包含一個truestatements集合、一個falsestatements集合和一個條件屬性(condition attribute),但不涉及條件語句塊要用“end if”還是右花括號“}”結束,這部分細節由codeprovider處理。有了這一層抽象,我們就可以描述待生成的代碼結構,然后將它以任意語言的形式輸出,卻不必斤斤計較于各種與特定語言有關的細節問題。同時,這種抽象也為我們通過程序改變代碼的結構帶來了方便。例如,當我們發現某個方法需要增加一個參數時,就可以將參數加入到該方法的parameters集合,根本無須改動已生成的代碼邏輯。 
   
  我們在本文中要用到的大部分對象來自system.codedom名稱空間,其余對象主要來自各個與特定語言有關的名稱空間,例如microsoft.csharp名稱空間、microsoft.visualbasic名稱空間、microsoft.jscript名稱空間和microsoft.vjsharp名稱空間。所有這些面向特定語言的名稱空間都包含各自的codeprovider對象。最后,system.codedom.complier名稱空間定義icodegenerator接口,后者用來把生成的代碼輸出到一個textwriter對象。 
   
  如果我們只要生成一些用于插件或宏的代碼片斷,可以利用codegenerator從statement、expression、type等生成代碼。反之,如果我們要生成的是一個完整的文件,則必須從codenamespace對象入手。在本文的例子中,我們將從一個名稱空間開始,示范如何加入import語句、聲明類、聲明方法、聲明變量、實現一個循環結構、索引一個數組,最后,我們將這些技術結合起來,得到一個大家都熟悉的程序。
  
    1.1 初始化名稱空間
  
    初始化名稱空間的代碼類似下面這種形式:
  
  private codenamespace initializenamespace(string name)
  {
   // 初始化codenamespace變量,指定名稱空間的名稱
   codenamespace currentnamespace = new codenamespace (name);
   // 將一些名稱空間加入到要導入的名稱空間集合。
   // 各種語言如何導入名稱空間的細節由每種語言對應
   // 的codeprovider分別處理。
   currentnamespace.imports.add (new codenamespaceimport("system"));
   currentnamespace.imports.add (new codenamespaceimport("system.text"));
   return currentnamespace;
  }
  
  
  
    這段代碼定義了一個新的名稱空間,并導入system和system.text名稱空間。
  
    1.2 創建類
  
    聲明一個新類的代碼類似下面這種形式:
  
  private codetypedeclaration createclass (string name)
  {
   // 新建一個codetypedeclaration對象,指定要創建的類的名稱
   codetypedeclaration ctd = new codetypedeclaration (name);
   // 指定這個codetype是一個類,而不是一個枚舉變量或struct
   ctd.isclass = true;
   // 這個類的訪問類型是public
   ctd.attributes = memberattributes.public;
   // 返回新創建的類
   return ctd;
  }
  
  
  
    createclass函數新建一個指定名稱的類,做好為該類植入方法、屬性、事件的準備。
  
    1.3 創建方法
  
    聲明一個新函數的代碼類似下面這種形式:
  
  private codeentrypointmethod createmethod()
  {
   // 創建一個方法
   codeentrypointmethod method = new codeentrypointmethod();
   // 指定該方法的修飾符:public,static
   method.attributes = memberattributes.public |
   memberattributes.static;
   // 返回新創建的方法
   return method;
  } 
   
  本例創建了一個codeentrypointmethod對象。codeentrypointmethod對象類似于codemembermethod對象,兩者的不同之處在于,codeprovider會將codeentrypointmethod代表的方法作為類的入口點調用,例如作為sub main或void main等。對于codeentrypointmethod對象,方法的名稱默認為main;對于codemembermethod,方法的名稱必須顯式指定。
  
    1.4 聲明變量
  
    聲明一個變量的代碼類似下面這種形式:
  
  private codevariabledeclarationstatement
   declarevariables(system.type datatype,
   string name)
  {
   // 為將要創建的變量類型創建一個codetypereference對象,
   // 這使得我們不必去關注該類數據在特定語言環境中的
   // 與數據類型有關的細節問題。
   codetypereference tr = new codetypereference (datatype );
   // codevariabledeclarationstatement對象使得我們不必糾纏于
   // 與特定語言有關的下列細節:在該語言的變量聲明語句中,
   // 應該是數據類型在前,還是變量名稱在前;聲明變量時是
   // 否要用到dim之類的關鍵詞.
   codevariabledeclarationstatement declaration =
   new codevariabledeclarationstatement(tr, name);
   // codeobjectcreateexpression負責處理所有調用構造器的細節。
   // 大多數情況下應該是new,但有時要使用new。但不管怎樣,
   // 我們不必去關注這些由語言類型決定的細節.
   codeobjectcreateexpression newstatement = new
   codeobjectcreateexpression ();
   // 指定我們要調用其構造器的對象.
   newstatement.createtype = tr;
   // 變量將通過調用其構造器的方式初始化.
   declaration.initexpression = newstatement;
   return declaration;
  } 
         
  每一種.net語言都有其特定的數據類型名稱,所有這些數據類型都被映射到公共的.net語言類型。例如,對于c#中稱為int的數據類型,在vb.net中是integer,公共的.net類型是system.int32。codetypereference對象直接使用.net公共數據類型,以后由每種語言的codeprovider將它轉換成符合各自語言規范的類型名稱。
  
    1.5 初始化數組
  
    初始化一個數組的代碼類似下面這種形式:
  
  private void initializearray (string name,
   params char[] characters )
  {
   // 從參數中傳入的字符數組獲得一個codetypereference 對象,
   // 以便在生成的代碼中復制該數據類型.
   codetypereference tr = new codetypereference (characters.gettype());
   // 聲明一個匹配原始數組的數組
   codevariabledeclarationstatement declaration =
   new codevariabledeclarationstatement (tr, name);
   // codeprimitiveexpression代表“基本”或值數據類型,
   // 例如char、int、double等等。
   // 我們將用這類基本數據類型構成的一個數組來
   // 初始化我們正在聲明的數組。
   codeprimitiveexpression[] cpe = new
   codeprimitiveexpression[characters.length];
   // 循環遍歷原始字符數組,
   // 為codeprimitiveexpression類型的數組創建對象。
   for (int i = 0; i < name.length ; i++)
   {
   // 每一個codeprimitiveexpression將有一個字符的語言
   // 中立的表示。
   cpe[i] = new codeprimitiveexpression (characters[i]);
   }
   // codearraycreateexpression負責調用數組中數據類型的
   // 默認構造器。
   // 由于我們還傳入了一個codeprimitiveexpression的數組,
   // 所以不必指定數組的大小,且數組中的每一個元素都將有
   // 合適的初值。
   codearraycreateexpression array = new
   codearraycreateexpression(tr, cpe);
   // 指定:該codearraycreateexpression將初始化數組變量聲明。
   declaration.initexpression = array;
   return declaration;
  }
  
  
  
    1.6 定義循環結構
  
    聲明一個循環結構的代碼類似下面這種形式:
  
  private codeiterationstatement createloop(string loopcontrolvariablename)
  {
   // 聲明一個新的變量,該變量將作為
   // 循環控制變量
   codevariabledeclarationstatement declaration;
   // 聲明一個管理所有循環邏輯的codeiterationstatement
   codeiterationstatement forloop = new codeiterationstatement();
   // 為動態聲明的變量指定數據類型的另一種方法:
   // 用typeof函數獲得該數據類型的type對象,不必
   // 用到該類數據的變量
   declaration = new codevariabledeclarationstatement(typeof (int),
   loopcontrolvariablename);
   // 指定一個簡單的初始化表達式:
   // 將新變量設置為0
   declaration.initexpression = new codesnippetexpression ("0");
   // 這個新聲明的變量將用來初始化循環
   forloop.initstatement = declaration;
   // codeassignstatement用來處理賦值語句。
   // 這里使用的構造器要求提供兩個表達式,第一個位于
   // 賦值語句的左邊,第二個位于賦值語句的右邊。
   // 另一種辦法是:調用默認的構造器,然后分別顯式設置
   // 左、右兩個表達式。
   codeassignstatement assignment = new codeassignstatement(
   new codevariablereferenceexpression(loopcontrolvariablename),
   new codesnippetexpression (loopcontrolvariablename + " + 1" ));
   // 在循環迭代中使用賦值語句。
   forloop.incrementstatement = assignment;
   // 當循環控制變量超出數組中的字符個數時,
   // 循環結束
   forloop.testexpression = new codesnippetexpression
   (loopcontrolvariablename + " < characters.length");
   return forloop;
  } 
   
   
   
  注意,這里我們用typeof函數直接獲得循環控制變量的數據類型的type對象,而不是通過聲明一個codetypereference對象的方式。這是codevariabledeclartionstatement的又一個構造器,實際上其構造器的總數多達7種。 
   
  1.7 索引數組 
   
  索引一個數組的代碼類似下面這種形式:
  
  private codearrayindexerexpression
   createarrayindex(string arrayname, string indexvalue )
  {
   // 新建一個codearrayindexerexpression
   codearrayindexerexpression index = new codearrayindexerexpression ();
   // indices屬性是一個能夠支持多維數組的集合。不過這里我們只需要
   // 一個簡單的一維數組。
   index.indices.add ( new codevariablereferenceexpression (indexvalue));
   // targetobject指定了要索引的數組的名稱。
   index.targetobject = new codesnippetexpression (arrayname);
   return index;
  } 
   
   
   
  codearrayindexerexpression對象處理數組索引方式的種種差異。例如,在c#中數組以arrayname[indexvalue]的方式索引;但在vb.net中,數組以arrayname(indexvalue)的方式索引。

  codearrayindexerexpression允許我們忽略這種差異,將注意力集中到其他更重要的問題,例如要索引哪一個數組、要訪問第幾個數組元素。 
   
  二、裝配出樹結構 
   
  我們可以把前面定義的所有函數加入到一個類,通過構造器初始化,例如:
  
  public codedomprovider()
  {
   currentnamespace = initializenamespace("testspace");
   codetypedeclaration ctd = createclass ("helloworld");
   // 把類加入到名稱空間
   currentnamespace.types.add (ctd);
   codeentrypointmethod mtd = createmethod();
   // 把方法加入到類
   ctd.members.add (mtd);
   codevariabledeclarationstatement variabledeclaration =
   declarevariables (typeof (stringbuilder), "sbmessage");
   // 把變量聲明加入到方法
   mtd.statements.add (variabledeclaration);
   codevariabledeclarationstatement array = initializearray
   ("characters", 'h', 'e', 'l', 'l', 'o', ' ',
   'w', 'o', 'r', 'l', 'd');
   // 把數組加入到方法
   mtd.statements.add (array);
   codeiterationstatement loop = createloop("intcharacterindex");
   // 把循環加入到方法
   mtd.statements.add (loop);
   // 數組索引
   codearrayindexerexpression index = createarrayindex("characters",
   "intcharacterindex");
   // 加入一個語句,它將調用sbmessage對象的“append”方法
   loop.statements.add (new codemethodinvokeexpression (
   new codesnippetexpression ("sbmessage"),"append",
   index));
   // 循環結束后,輸出所有字符追加到sbmessage對象
   // 后得到的結果
   mtd.statements.add (new codesnippetexpression
   ("console.writeline (sbmessage.tostring())"));
  } 
   
   
   
  構造器的運行結果是一個完整的codedom樹結構。可以看到,至此為止我們的所有操作都獨立于目標語言。最后生成的代碼將以屬性的形式導出。 
   
  三、輸出生成結果 
   
  構造好codedom樹之后,我們就可以較為方便地將代碼以任意.net語言的形式輸出。每一種.net語言都有相應的codeprovider對象,codeprovider對象的creategenerator方法能夠返回一個實現了icodegenerator接口的對象。icodegenerator接口定義了用來生成代碼的所有方法,而且允許我們定義一個用來簡化屬性輸出的輔助方法。下面的輔助方法generatecode負責設置好合適的textwriter以供輸出代碼,以字符串的形式返回結果文本。
  
  private string generatecode (icodegenerator codegenerator)
  {
   // codegeneratoroptions允許我們指定各種供代碼生成器
   // 使用的格式化選項
   codegeneratoroptions cop = new codegeneratoroptions();
   // 指定格式:花括號的位置
   cop.bracingstyle = "c";
   // 指定格式:代碼塊的縮進方式
   cop.indentstring = " ";
   // generatecodefromnamespace要求傳入一個textwriter以
   // 容納即將生成的代碼。這個textwriter可以是一個streamwriter、
   // 一個stringwriter或一個indentedtextwriter。
   // streamwriter可用來將代碼輸出到文件。
   // stringwriter可綁定到stringbuilder,后者可作為一個變量引用。
   // 在這里,我們把一個stringwriter綁定到stringbuilder sbcode。
   stringbuilder sbcode = new stringbuilder();
   stringwriter sw = new stringwriter(sbcode);
  
   // 生成代碼!
   codegenerator.generatecodefromnamespace(currentnamespace, sw,cop);
   return sbcode.tostring();
  } 
      
    有了這個輔助函數,要獲取各種語言的代碼就相當簡單了:
  
  public string vbcode
  {
   get
   {
   vbcodeprovider provider = new vbcodeprovider ();
   icodegenerator codegen = provider.creategenerator ();
   return generatecode (codegen);
   }
  
  }
  
  public string jscriptcode
  {
   get
   {
   jscriptcodeprovider provider = new jscriptcodeprovider ();
   icodegenerator codegen = provider.creategenerator ();
   return generatecode(codegen);
   }
  
  }
  
  public string jsharpcode
  {
   get
   {
   vjsharpcodeprovider provider = new vjsharpcodeprovider ();
   icodegenerator codegen = provider.creategenerator ();
   return generatecode (codegen);
   }
  
  }
  
  public string csharpcode
  {
   get
   {
   csharpcodeprovider provider = new csharpcodeprovider();
   icodegenerator codegen = provider.creategenerator ();
   return generatorcode (codegen);
   }
  
  } 
   
   
   
  四、顯示出生成的代碼 
   
  為輸出代碼,我們要用到一個簡單的.aspx文件,它有四個標簽,分別對應一種.net語言:
  
  <table width="800" border="1">
   <tr>
   <th>vb.net代碼</th>
   </tr>
   <tr >
   <td>
   <asp:label id="vbcode" runat="server" cssclass="code">
   </asp:label>
   </td>
   </tr>
   <tr>
   <th>
   c#代碼</th></tr>
   <tr>
   <td><asp:label id="csharpcode" runat="server" cssclass="code">
   </asp:label></td>
   </tr>
   <tr>
   <th>j#代碼</th></tr>
   <tr >
   <td>
   <asp:label id="jsharpcode" runat="server" cssclass="code">
   </asp:label>
   </td>
   </tr>
   <tr>
   <th>jscript.net代碼</th>
   </tr>
   <tr>
   <td><asp:label id="jscriptcode" runat="server" cssclass="code">
   </asp:label></td>
   </tr>
  </table> 
      
  在后臺執行的代碼中,我們實例化一個前面創建的codedomprovider類的實例,把它生成的代碼賦值給.aspx頁面的相應標簽的text屬性。為了使web頁面中顯示的代碼整齊美觀,有必要做一些簡單的格式化,替換換行符號、空格等,如下所示:
  
  private string formatcode (string codetoformat)
  {
   string formattedcode = regex.replace (codetoformat, "/n", "<br>");
   formattedcode = regex.replace (formattedcode, " " , " ");
   formattedcode = regex.replace (formattedcode, ",", ", ");
   return formattedcode;
  } 
   
   
   
  下面把生成的代碼顯示到web頁面:
  
  private void page_load(object sender, system.eventargs e)
  {
  
   helloworld.codedomprovider codegen = new helloworld.codedomprovider ();
   vbcode.text = formatcode (codegen.vbcode);
   csharpcode.text = formatcode (codegen.csharpcode);
   jscriptcode.text = formatcode (codegen.jscriptcode);
   jsharpcode.text = formatcode (codegen.jsharpcode);
   page.enableviewstate = false;
  }
  
  
  
    輸出結果如下:
  
  vb.net代碼
  
  imports system
  imports system.text
  
  namespace helloworld
  
   public class hello_world
  
   public shared sub main()
   dim sbmessage as system.text.stringbuilder = _
   new system.text.stringbuilder
   dim characters() as char = new char() {_
   microsoft.visualbasic.chrw(72), _
   microsoft.visualbasic.chrw(69), _
   microsoft.visualbasic.chrw(76), _
   microsoft.visualbasic.chrw(76), _
   microsoft.visualbasic.chrw(79), _
   microsoft.visualbasic.chrw(32), _
   microsoft.visualbasic.chrw(87), _
   microsoft.visualbasic.chrw(79), _
   microsoft.visualbasic.chrw(82), _
   microsoft.visualbasic.chrw(76), _
   microsoft.visualbasic.chrw(68)}
   dim intcharacterindex as integer = 0
   do while intcharacterindex < characters.length
   sbmessage.append(characters(intcharacterindex))
   intcharacterindex = intcharacterindex + 1
   loop
   console.writeline (sbmessage.tostring())
   end sub
   end class
  end namespace
  
  c#代碼
  
  namespace helloworld
  {
   using system;
   using system.text;
  
   public class hello_world
   {
   public static void main()
   {
   system.text.stringbuilder sbmessage = new
   system.text.stringbuilder();
   char[] characters = new char[] {
   'h',
   'e',
   'l',
   'l',
   'o',
   ' ',
   'w',
   'o',
   'r',
   'l',
   'd'};
   for (int intcharacterindex = 0;
   intcharacterindex < characters.length;
   intcharacterindex = intcharacterindex + 1)
   {
   sbmessage.append(characters[intcharacterindex]);
   }
   console.writeline (sbmessage.tostring());
   }
   }
  }
  
  j#代碼
  
  package helloworld;
  import system.*;
  import system.text.*;
  
  
  public class hello_world
  {
   public static void main(string[] args)
   {
   system.text.stringbuilder sbmessage = new
   system.text.stringbuilder();
   char[] characters = new char[]
   {
   'h',
   'e',
   'l',
   'l',
   'o',
   ' ',
   'w',
   'o',
   'r',
   'l',
   'd'}
   ;
   for (int intcharacterindex = 0;
   intcharacterindex < characters.length;
   intcharacterindex = intcharacterindex + 1)
   {
   sbmessage.append(characters[intcharacterindex]);
   }
   console.writeline (sbmessage.tostring());
   }
  }
  
  
  jscript.net代碼
  
  
  //@cc_on
  //@set @debug(off)
  
  import system;
  import system.text;
  
  package helloworld
  {
  
   public class hello_world
   {
  
   public static function main()
   {
   var sbmessage : system.text.stringbuilder =
   new system.text.stringbuilder();
   var characters : char[] =
   ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'];
   for (var intcharacterindex : int = 0;
   ; intcharacterindex < characters.length;
   intcharacterindex = intcharacterindex + 1)
   {
   sbmessage.append(characters[intcharacterindex]);
   }
   console.writeline (sbmessage.tostring());
   }
   }
  }
  helloworld.hello_world.main(); 
   
  總結:codedom體現了.net中語言的重要性不如框架的思想。本文示范了如何運用一些常用的codedom類,幾乎每一個使用codedom技術的應用都要用到這些類。作為一種結構化的代碼生成技術,codedom有著無限的潛能,唯一的約束恐怕在于人們的想象力。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 射洪县| 前郭尔| 陈巴尔虎旗| 黄大仙区| 大洼县| 齐齐哈尔市| 海盐县| 禹城市| 察隅县| 七台河市| 肇庆市| 湖北省| 彰武县| 陵水| 太和县| 阳高县| 梁河县| 安陆市| 太湖县| 海晏县| 巨野县| 锡林浩特市| 莱阳市| 定兴县| 白水县| 临漳县| 东丰县| 张家港市| 凤凰县| 彭阳县| 承德县| 漳浦县| 汽车| 共和县| 焦作市| 巴彦淖尔市| 阜平县| 霍邱县| 黎川县| 阳谷县| 磐石市|