代碼產生器與 .NET

來源:互聯網
上載者:User
http://www.microsoft.com/china/msdn/library/langtool/vsdotnet/realworld11022004.mspx

代碼產生器與 .NET發布日期: 12/23/2004 | 更新日期: 12/23/2004

Pierre Couzy
WinWise

摘要:代碼產生器是您日常生活中的一部分,即使您沒有意識到這一點。Pierre Couzy 說明了如何在項目中利用它們。

本頁內容
簡介
工具和樣本
版本控制
小結

簡介

假設您在一家由 DBA 統治一切的公司裡工作:您不能產生只是“到 Oracle 那裡去取一些記錄”的應用程式。您只能依靠預存程序,因為在該層級存在安全層。

產生應用程式通常涉及到下列步驟:

1.

建立一批預存程序。

2.

建立能夠與預存程序通訊的 C# 類。

3.

建立將管理 Microsoft ASP.NET 表單或 Microsoft Windows 表單或者形成另一個層的更進階別的類。

步驟 1 和步驟 2 是密切相關的:它們共用大量結構,它們消耗另一個步驟所產生的東西,等等。問題在於,您擁有兩種不同的語言(在該樣本中,為 PL-SQL 和 C#),並且無法從其中一種語言引用另一種語言。

您說這沒有什麼大不了的?團隊中的第一個開發人員將使一切保持正常,因為他瞭解 .NET、PL/SQL 以及安全模型的本質。他可能將編寫兩個東西:首先是一組協助器類,然後是一個有效樣本 — 於是,其他開發人員將使用這些協助器類,複製/粘貼有效樣本,並針對他們的需要進行修改。

如果您已經在軟體行業中工作了足夠長的時間,就會知道接下來將會發生什麼事情:隨著要求的增加,協助器類將慢慢變大,並且其中一些將很快過時。當然,沒有人敢於修改它們,因為這可能會毀壞較舊的項目。同時,開發人員將重用不再與新規則同步的有效樣本,並且他們將沒有辦法瞭解哪些部分仍在使用,以及哪些部分可以毫無風險地丟棄。您將陷入一片混亂之中(複製/粘貼編程)。

有很多克服這一複雜性的辦法,而我將介紹您可能已經忽視的一種有用的辦法 — 代碼產生器。其實您已經使用了它們,即使您沒有意識到這一點:每當您建立一個新的 ASPX 頁時,隱藏機制就會將它轉換為 C# 或 Microsoft Visual Basic 類。當您在項目中引用 COM 組件、Web 服務甚至資料結構(類型化資料集)時,會發生相同的事情 — 有一個類被自動產生,它隱藏了您不希望瞭解的複雜性。

返回頁首

工具和樣本

您將遇到的第一批代碼產生器只是一些隱藏複雜性的工具。它們不允許您解釋如何產生代碼,並且不讓您隨後更改產生的程式碼(它們將清除您進行的更新)。

例如,“Add Web Reference Wizard”甚至不向您顯示插入到項目中的代碼(除非您請求它顯示)。

圖 1. 顯示為 Web 參考產生的程式碼

Windows 表單設計器也是一個代碼產生器。在這裡,您可以查看代碼,但最好不要動它。

     #region Windows Form Designer generated code      /// <summary>      /// Required method for Designer support - do not modify      /// the contents of this method with the code editor.      /// </summary>      private void InitializeComponent()      {         this.button1 = new System.Windows.Forms.Button();         this.SuspendLayout();

讓我們更進一步地探討該問題:代碼產生器可以提供格式規範的主幹,以供您隨後添加自己的代碼。您可能知道 Reflector,但您是否知道 Reflector 的一些增益集 (http://www.dotnetwiki.org/Default.aspx?tabid=52) 包含代碼產生器?它們使您可以執行以下工作:

圖 2. 使用 Reflector 產生代碼

當您按下“Generate”按鈕時,將建立一個新檔案:

// Generated by Reflynamespace MyTestNameSpace{    using System;            /// <summary>Test fixture for the <see cref="SomeBusinessClass"/> class    ///</summary>    /// <remarks />    [TestFixture()]    public class SomeBusinessClassTest    {                /// <summary />        /// <remarks />        private SomeBusinessClass _someBusinessClass = null;                /// <summary />        /// <remarks />        public virtual SomeBusinessClass SomeBusinessClass        {            get            {                return this._someBusinessClass;            }        }                /// <summary>Tests the EstimateSomeNumber method</summary>        /// <remarks>        ///   <para>Test coverage (estimated): 100,0%</para>        ///   <para>Target path:</para>        ///   <code>/* 0 */ return 0x2a;        /// </code>        /// </remarks>        [Test()]        [Ignore()]        public virtual void EstimateSomeNumber0()        {            throw new System.NotImplementedException();        }                /// <summary>Tests the IsSomethingAlreadyInDataBase method</summary>        /// <remarks>        ///   <para>Test coverage (estimated): 100,0%</para>        ///   <para>Target path:</para>        ///   <code>/* 0 */ return false;        /// </code>        /// </remarks>        [Test()]        [Ignore()]        public virtual void IsSomethingAlreadyInDataBase0()        {            throw new System.NotImplementedException();        }                /// <summary>Sets up the fixture</summary>        /// <remarks />        [SetUp()]        public virtual void SetUp()        {            throw new System.NotImplementedException();        }                /// <summary>Releases resource allocated in the fixture</summary>        /// <remarks />        [TearDown()]        public virtual void TearDown()        {            throw new System.NotImplementedException();        }    }}

您不瞭解有關“單元測試”的任何內容,但是您仍然能夠產生有效測試類別。與上一個樣本的不同之處在於,這一次您必須在產生的類的內部編碼。可是,我們仍然無法建立我們自己的模板。

下一個步驟是建立我們自己的代碼產生器。我們需要的全部東西就是一種根據一組常用資訊(例如,將要獲得的列的名稱、要用來請求資訊的方式、要允許的事務種類等等)來產生文字檔(C#、PL-SQL 等等)的方式。當然,您無法產生所有東西,因此需要一個能夠產生自訂主乾的工具,而某個開發人員隨後將添加特定的實現細節。

該工具可以是 Perl、Microsoft VBScript 或普通的舊式 ASP(就本文而言)— 畢竟,它是一種可以根據參數產生文字檔的很好的工具。您可能使用 ASP 產生 HTML 檔案,但是它還適用於產生 Microsoft Excel 或 CSV、WML — 因此,為什麼不用它來產生 T-SQL 或 C# 呢?

您的 ASP 檔案可能如下所示:

<%@ Language=VBScript %><%if request("Generate").count = 0 then%><HTML><BODY>   <form method=post>   <P>Property name :<INPUT name=PropertyName></P>   <P>What is the type of your property ? <INPUT name=PropertyType></P>   <P>Read only <input type=checkbox name=ReadOnly value=true></P>   <P><INPUT type=submit value="Generate !" name=Generate></P>   </form></BODY></HTML><% else dim PropertyName, PropertyType, ReadOnly, PropertyModifierPropertyName = Request("PropertyName")PropertyType = Request("PropertyType")ReadOnly = (Request("ReadOnly")="true")if ReadOnly then PropertyModifier = "ReadOnly" else PropertyModifier = ""Response.ContentType = "text/plain"%>Private _<%=PropertyName%> as <%=PropertyType%>Public <%=propertyModifier%> Property <%=PropertyName%> as <%=PropertyType%>   Get      Return _<%=PropertyName%>   End Get<%if not ReadOnly then%>   Set (ByVal Value as <%=PropertyType%>)      _<%=PropertyName%> = Value   End Set<%end if%>End Property<%end if%>

當您執行該檔案時,您將獲得如下所示的內容:

圖 3. 產生的 Web 頁

圖 4. 產生的程式碼

您還可以在 Internet 上找到代碼產生器。我通常使用 CodeSmith;它是免費的並且易於理解,但是您可以找到很多其他的代碼產生器。圖 5 是一個螢幕,它顯示了一種等待泛型的聰明方式;它產生一個強型別的雜湊表。

圖 5. CodeSmith

這些工具通常接受兩個輸入 — 一個模板檔案(像我們的 ASP 檔案)和一個 XML 參數檔案(像表單的內容),併產生一個新檔案。

開發人員被賦予這些模板,並且他們通常通過同一組參數來使用兩個不同的模板。這樣,他們將相同的資訊給予這兩個模板,並且獲得共用資訊的一個 T-SQL 檔案和一個 C# 檔案,同時無需承擔遺忘或鍵入錯誤的風險;這樣就為您完成了此工作的乏味部分。

返回頁首

版本控制

當然,在使用模板和自動產生的程式碼時,事情會變得複雜。在現實生活中,模板會演化(例如,您可能希望賦予 C# 類一種調用某些預存程序的非同步方式);如果是這樣,那麼您需要一種相應的辦法,以應付開發人員在主幹產生之後放入的實現。

為此,您必須確保開發人員添加的代碼獨立於您的模板所產生的程式碼。實現此目的最簡單的技術是建立兩個不同的類:一個用於產生的程式碼,另一個從第一個繼承,但將不產生。

圖 6. 對產生的程式碼進資料列版本設定

由於該技術所具有的繼承機制,因此它在您產生 .NET 代碼時非常適用;但是,如果您要產生其他種類的代碼(VBScript、SQL),則將無法以這種方式工作。在那種情況下,您主要依靠自己來解決問題。我使用的機制很簡單:我在產生的程式碼中提供了預留位置(在 C# 中為地區;在 SQL 中為特定注釋所圍繞的塊),並且當代碼被重建時,只有這些地區中的代碼被保留。傳輸自訂代碼本身同樣簡單:模板始終接受 PreviousFile 參數。當該參數存在時,將分析以前的檔案以獲得自訂代碼,並將其重新插入到當前的組建檔案中。

如果沒有辦法恢複原樣,則千萬不要弄亂產生的程式碼:您將發現自己進行中複製/粘貼編程。

返回頁首

小結

下面是在使用代碼產生器時需要記住的一些事情:

•

如果不打算對產生的程式碼進行修改,請預先聲明。

•

不要忘記,開發人員沒有時間瞭解產生代碼的內部結構,因此請為他們提供協助,並且儘可能詳細地對進入點進行說明。

•

考慮進資料列版本設定,並明確說明您將允許人們做什麼。或許您希望開發人員只在代碼的特定地區中添加自訂代碼,或者您希望他們從您的類繼承。

•

模板的新版本應當始終能夠重建舊版本所產生的程式碼。如果新版本需要比舊版本更多的代碼以便正確工作,則請將需要代碼的位置變得明顯一些,並且插入一些能夠建置錯誤的代碼(在編譯時間 — 如果可能的話)。

•

如果您決定中斷模板的版本控制機制(例如,通過添加在應用新版本時無法恢複原樣的代碼),請保留該模板和您使用的參數的副本。如果您需要為某箇舊項目產生另一個類似的代碼檔案,並且您已經丟失了在開發該舊項目時使用的模板版本,則會發生很糟糕的事情。我只是將模板和參數與項目一起放在 SourceSafe 中。

•

在發布模板之前,對其進行徹底的測試。模板會在開發人員之間飛快地傳播,因為他們無需多少知識就可以解決問題。如果更新產生的檔案意味著丟失自訂,那麼程式錯誤將很難尋找,並且更加難以修複。

使用該方法能夠走多遠?簡單說來,代碼產生器使開發人員可以獲得一個抽象層級。他不必將精力集中於技術過程(因為該過程已嵌入到模板中),並且可以考慮整合該過程。它使開發人員能夠更好地理解客戶需求,並使技術過程擁有更好的品質。Microsoft Visual Studio 已經廣泛使用了這些技術,並且即將問世的版本已經添加了很多改進(令人信服的是一個類建模程式和不完整類機制,可用於將產生的程式碼與自訂代碼分隔開)。

現實世界中的 .NET

Pierre Couzy 是一個專門研究分布式系統體繫結構的培訓師和顧問。作為 20 餘部書籍的作者,他目前被 WinWise 聘為 ASP.NET 和 BizTalk 專家。他自 2003 年以來一直是地區主管,並且在法國的許多重要會議上發表了演講。如果您要與他討論法國爵士、橋牌(是的,就是那種簡單的遊戲)甚至電腦,請通過 Pierre.couzy@winwise.fr 與他聯絡。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.