利用 RazorEngine 打造簡單的泛用代碼生成器

自從 ASP.NET MVC 3 推出來之後,其中最大的亮點當數 MVC 3 裏的 Razor 頁面引擎。用 @{ } 取代了以前的 <%= %>,簡潔的語法讓開發者讚不絕口。
和 MVC 開源一樣,Codeplex 上也開源了這個引擎:RazorEngine , 熟悉MVC開發的童鞋都知道這其中的奧祕,主要是使用了.NET 4.0 dynamic 動態對象。
然後 RazorEngine 會將 template 生成一個臨時的 .cs 文件,然後編譯並調用。

說到代碼生成,大家可能都會想到 T4,可惜的是 T4 需要預編譯。
那麼就先來看看 t4 如何運行時獲得結果的代碼:
首先添加一個 HelloWorld.tt 內容如下:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ parameter name="name" type="System.String" #>
Hello <#= name#> Welcome to t4! 
修改 tt 的 Customer Tool 屬性:TextTemplatingFileGenerator 改爲 TextTemplatingFilePreprocessor 保存之後,會自動生成一個 HelloWorld.cs 文件。
然後就可以在代碼中動態獲得結果了:
HelloWorld t4Template = new HelloWorld();
t4Template.Session = new Dictionary<string, object> { { "name", "World" } };
t4Template.Initialize();
string result = t4Template.TransformText();
不難看出,T4 的模板需要預編譯,生成模板的靜態類型再動態傳入值生成結果。所以難以達到動態添加,修改模板的要求。
(msdn:使用預處理 T4 文本模板生成運行時文本

再來看看 RazorEngine :
string template = "Hello @Model.Name! Welcome to Razor!";
string result = Razor.Parse(template, new { Name = "World" });
沒有預編譯,只需要動態的傳值,字符串即模板。這就給模板的變化帶來極大的想象空間,比如:在線的模板修改保存,提供數據並生成結果。

接下來看看如何利用 Razor 打造一個泛用的代碼生成器:


定義兩個輸入區域,一個是“全局數據”,一個是“列表數據”。全局數據輸入單值即不循環的,列表數據是多行的用於循環輸出。
模板頁可以隨時修改,保存。模板裏的變量當然是根據前面的輸入來定義的,總是要有規律的嘛。


輸出的效果

這樣任何項目,只要隨時定義模板就可即時獲得結果,也不要編譯。
其實實現也很簡單:輸入的全局數據和多行數據(第一行數據作爲 dynamic 對象的屬性)解析後填充到 ExpandoObject 裏交給 Razor 就可以了~

private List<dynamic> ParseListData(string content, char[] separator)
{
    var datas = new List<dynamic>();
    var lines = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

    if (lines.Length <= 0)
        return datas;

    string[] columns = null;
    int index = 0;

    foreach (var line in lines)
    {
        var handledline = line;
        if (separator.Any(c => c == ' '))
        {
            handledline = Regex.Replace(line, "\\s+", " ");
        }

        if (index == 0)
        {
            columns = handledline.Split(separator, StringSplitOptions.RemoveEmptyEntries);
            columns = columns.Select(col => col.Trim()).ToArray();
        }
        else
        {                    
            var fieldValues = handledline.Split(separator);
            dynamic obj = new ExpandoObject();
            var dict = (IDictionary<string, object>)obj;
            for (int i = 0; i < fieldValues.Length; i++)
            {
                dict[columns[i].Trim()] = fieldValues[i].Trim();
            }
            datas.Add(obj);
        }
        index++;
    }
    return datas;
}

其實對於javascript, ruby, python 這樣的動態語言,實現上面的功能也不是什麼難事。但 Razor 不僅僅提供了動態的編譯,還有一個強大的模板解析的功能。
利用 @help 還可以在模板裏提供一些輔助方法。這樣看來 Razor 也算是 C# DSL 的一種實現了。






發佈了143 篇原創文章 · 獲贊 10 · 訪問量 127萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章