Razor Engine,實現代碼生成器的又一件利器
Razor Engine,之前僅僅是ASP.NET MVC的一種View引擎,目前已經完全成為一種可以獨立使用的模版引擎,並且已經成為了CodePlex上一個開源的項目(https://razorengine.codeplex.com/)。對於使用過ASP.NET MVC Razor視圖引擎的朋友們一定已經領略過它的靈活性和易用性,在這篇文章中我們將利用它來實現一個代碼生成器使我們可以以Razor的語法來定義代碼模版。[源代碼從這裏下載]
在《一個簡易版的T4代碼生成"框架"》這篇文章中,我創建了一個能夠生成多個文件的代碼生成器,其核心是兩個基本的類型:Template類生成代碼文件的內容,Generator執行Template。現在我將通過自定義一個基於Razor Engine的Template,讓它讀取以Razor語法編寫的模版文件並生成相應的代碼。
不過在具體介紹實現原理之前,還是先來看看它能夠達到的效果。如右圖所示,我們還是通過一個.tt文件(Generator.tt)來生成相應的代碼文件,具體生成的代碼文件就是依賴於該.tt文件的三個.cs 文件:Foo.cs、Bar.cs和Baz.cs。簡單起見,我們僅僅在這三個文件中生成了一個與文件同名的空Class,它們的定義如下。
1: public class Foo
2: {
3: }
4:
5: public class Bar
6: {
7: }
8:
9: public class Baz
10: {
11: }
如下所示的是Generator.tt的內容,它直接執行一個類型為DemoGenerator的生成器。
1: <#@ template hostspecific="true" language="C#" #>
2: <#@ assembly name="$(TargetDir)Artech.CodeGeneration.dll" #>
3: <#@ import namespace="Artech.CodeGeneration" #>
4: <#@ output extension=".empty" #>
5: <#this.RunCodeGenerator(this.Host, new DemoGenerator());#>
作為代碼生成器的DemoGenerator定義如下,它重寫了CreateTemplates方法並返回一個包含三個RazorTemplate<TModel>的字典,該字典的Key表示生成的文件名。
1: public class DemoGenerator: Generator
2: {
3: protected override IDictionary<string, Template> CreateTemplates()
4: {
5: Dictionary<string, Template> templates = new Dictionary<string, Template>();
6: templates.Add("Foo.cs", new RazorTemplate<string>("template.razor", "Foo"));
7: templates.Add("Bar.cs", new RazorTemplate<string>("template.razor", "Bar"));
8: templates.Add("Baz.cs", new RazorTemplate<string>("template.razor", "Baz"));
9: return templates;
10: }
11: }
構建RazorTemplate<TModel>需要傳入兩個參數,第一個參數是用於定義Razor模版的文件路徑(可以是絕對路徑,也可以是相對於.tt文件的相對路徑),另一個是作為Model的對象(相當於ASP.NET強類型View的Model)。通過上麵的代碼可以看出,三個RazorTemplate<TModel>均使用同一個Model類型為字符串的模版文件template.razor,該模版內容定義如下。可以看出作為Model的字符串在模版中作為了生成類型的名稱。
1: public class
2: {
3: }
我假設你已經了解了《一個簡易版的T4代碼生成"框架"》這篇文章的內容,所以我們隻需要簡單介紹RazorTemplate<TModel>的定義就可以了。首選RazorTemplate<TModel>是一個具有如下定義的RazorTemplate類型的子類。RazorTemplate的隻讀屬性TemplateFileName 表示Razor模版的路徑,用於讀取模版文本內容的虛方法GetTemplateText直接讀取指定模版文件的內容。在重寫的TransformText方法中,我們調用Razor的靜態方法Parse對模版內容進行解析並生成代碼文本。
1: public class RazorTemplate : Template
2: {
3: public string TemplateFileName { get; private set; }
4: public RazorTemplate(string templateFileName)
5: {
6: this.TemplateFileName = templateFileName;
7: }
8: protected virtual string GetTemplateText()
9: {
10: string path = this.TemplateFileName;
11: if (!Path.IsPathRooted(path))
12: {
13: path = Path.Combine(Path.GetDirectoryName(TransformContext.Current.Host.TemplateFile), path);
14: }
15: return File.ReadAllText(path);
16: }
17:
18: public override string TransformText()
19: {
20: return Razor.Parse(this.GetTemplateText());
21: }
22: }
繼承自RazorTemplate的泛型RazorTemplate<TModel>定義如下。它具有一個表示Model的隻讀屬性,該屬性在構造函數中被初始化。在重寫的TransformText方法中,我們調用Razor泛型的靜態方法Parse<TModel>解析模版文本並傳入Model對象。
1: public class RazorTemplate<TModel> : RazorTemplate
2: {
3: public TModel Model { get; private set; }
4: public RazorTemplate(string templateFileName, TModel model)
5: : base(templateFileName)
6: {
7: this.Model = model;
8: }
9:
10: public override string TransformText()
11: {
12: return Razor.Parse<TModel>(this.GetTemplateText(), this.Model);
13: }
14: }
相關閱讀:
與VS集成的若幹種代碼生成解決方案[博文匯總(共8篇)]
通過CodeDOM定義生成代碼的結構
通過Visual Studio的Custom Tool定義代碼生成器
不同於CodeDOM的代碼生成機製——T4
通過T4模板實現單文件的代碼生成
通過T4模板實現多文件的代碼生成
解決T4模板的程序集引用的五種方案
編寫T4模板進行代碼生成無法避免的兩個話題:"Assembly Locking"&"Debug"
通過自定義BuildProvider為ASP.NET提供代碼生成
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-25 15:34:14