日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ORM框架-工具-产品开发之四 开发代码生成器 Template Studio Development (一)

發布時間:2024/1/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ORM框架-工具-产品开发之四 开发代码生成器 Template Studio Development (一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天進入ORM工具開發系列的代碼生成工具的開發。現在流行的代碼生成工具,一般是基于模板的。T4,Code Smith在基于模板的代碼生成方面相當流行。ORM工具,需要從不同的數據庫中讀取元數據,調用代碼生成模板,生成代碼。

先來看一下代碼生成器的界面,邊看邊說。

界面是采用文章《Management Console 工具管理類軟件通用開發框架(開放源碼)》中提到的代碼框架,加上停靠的Output窗口,輸出編譯錯誤和調試信息,Properties窗體,用于解析屬性,設置屬性值,Server Explorer用來連接數據庫獲取元數據,調用代碼生成模板。

?

文件格式

模板的文件的第一種格式是《Write your own Code Generator or Template Engine in .NET》中提到的技術,把引用的程序集,和引用的命名空間,都放到文件中。這樣,文件肯定不能是文本格式的,它是模板對象的Xml序列化格式。

Input是模板的內容,References引用的程序集。Using_Libraries是導入命名空間,C#為using,VB.NET是Import。

這種格式,在開始開發模板生成器時,我采用這種格式。但是,后來發現效率不好,每次打開和關閉文件時,都需要序列化為Base64編碼,這需要耗費時間,另外,這種格式不支持Notepad來編輯,不是純文件,不方便編輯。

經過對第一種格式的改良,學習Code Smith格式模板的格式,采用文本格式作為模板文件的格式。看起來是這樣

<%@ Assembly Name="TestClassLibrary" %>
<%@ Import Namespace="EPN.Common" %>

public class Jack
{
??? public void Main()
??? {
??????? int key=System.Console.ReadKey();
??? }
}

這樣,將引用的程序集和導入的命名空間,放到模板中。這樣,簡化了模板的寫法,但是,會增加很多編譯的設置工作。

?

模板語法

模板生成器的基本原理是,將模板生成為一個類型,調用它生成的程序集的代碼,輸入結果。根據接觸到的LLBL Gen 3.x的模板語法和Code Smith的模板語法,ASP.NET的Page頁面文件,模板的語法看起來是這樣

<%@ Property Name="IncludeDrop" Type="System.Boolean" Default="True" Category="Options" Description="If true drop statements will be generated to drop existing stored procedures." %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data" %>

<%
string property1= "DemoClass";

%>
Current DateTime is: <%=DateTime.Now%>
Test Property :<%=IncludeDrop%>
<% for(int i=0;i<10;i++) { %>
???????? <%=Math.ApplictionName%> <%=i%>
??????? <% } %>

這里取自于Code Smith的語法。我寫的這個Template Studio也可以解析有Code Smith的模板,語法與之相似。

Property 標簽用來定義屬性,以便接受用戶的輸入,應用到模板中。這個值,在解析模板時,會解析有成為類型的變量,以便于使用。 這里有支持三種類型的屬性,Boolean,String,Int32。語法如下所示

<%@ Property Name="IncludeInsert" Type="System.Boolean" Default="True" Category="Options" Description="If true insert statements will be generated." %>
<%@ Property Name="IncludeUpdate" Type="System.String" Default="CNBLOGS" Category="Options" Description="If true update statements will be generated." %>
<%@ Property Name="IncludeDelete" Type="System.Int32" Default="123" Category="Options" Description="If true delete statements will be generated." %>

這樣說可能還不太明白,請看一下面的圖

解析引擎會分析到模板有三個參數,會在右邊的Properties窗體中顯示出來,并且提供值,讓用戶重新輸入,這樣達到動態變量的目的。在運行模板時,會把這個值傳到模板生成的代碼中去。

再來看,如何定義類型變量,而不是簡單類型。模板舉例如下

<%@ Property Name="Math" Type="MathProgram"? Category="Text"Description="Namespace for this class" %>

<%@ Assembly Name="TestClassLibrary" %>
<%@ Import Namespace="EPN.Common" %>

public class Jack
{
??? public void Main()
??? {
??????? int key=System.Console.ReadKey();
?????? <%=Math.SystemName%>
??????? <% for(int i=0;i<10;i++) { %>
???????? <%=Math.ApplictionName%> <%=i%>
??????? <% } %>
??? }
}

和添加普通的簡單類型變量一樣,MathProgram是類型名稱,Math是屬性名,因為是類型,所以加上Assembly以指明類型所在的程序集,Import指明類型所在的命名空間,這兩個值可以唯一確定一個類型。

來看類型MathProgram的定義,

[TypeConverter(typeof(ExpandConverter))]
public class MathProgram
{
????? public MathProgram(string system,string application)
????? {
????????? _SystemName = system;
????????? _ApplictionName = application;
????? }

?????? public MathProgram(){}

?????? private string _SystemName;
????? [Browsable(true)]
????? [Category("Text")]
????? [DefaultValue("")]
????? [Description("Namespace for this class")]
????? public string SystemName
????? {
????????? get { return _SystemName; }
????????? set { _SystemName = value; }
????? }

????? private string _ApplictionName;

????? [Browsable(true)]
????? [Category("Text")]
????? [DefaultValue("")]
????? [Description("Namespace for this class")]
????? public string ApplictionName
????? {
????????? get { return _ApplictionName; }
????????? set { _ApplictionName = value; }
????? }

}

解析后的效果是這樣

為什么要這么定義? 我來簡化一下它的寫法,本來是可以這樣寫的,我初始的想法是這樣的版本

public class MathProgram
{
????? public MathProgram(string system,string application)
????? {
????????? _SystemName = system;
????????? _ApplictionName = application;
????? }

????? public string _ApplictionName;

??????? public string _SystemName;

}

PropertyGrid控件,不認識變量成員定義,只認識屬性,Refactor—>Encapsulate Field變成屬性。
還要加上[Browsable(true)],以指示在PropertyGrid控件中顯示,[Category("Text")]是解析自它的屬性聲明,
[DefaultValue("")]和[Description("Namespace for this class")]也是一樣的原理。

MathProgram的定義還加上了聲明式的特性[TypeConverter(typeof(ExpandConverter))],目的是為了在PropertyGrid中展開顯示,如果沒有這個特性,它在PropertyGrid中是只讀的,顯示為灰色。

最后要提到的模板語法內容,是ASP.NET樣式的代碼片段,像這樣

<% for(int i=0;i<10;i++) { %>
???????? <%=Math.ApplictionName%> <%=i%>
??????? <% } %>

<%和%>之間的代碼,會原封不動的Render到生成的類型中,以用于解析成可執行的代碼。

?

與.NET屬性窗口交互的RAD組件

屬性的解析,生成,獲取用戶輸入的屬性值,是模板生成器的一項重要的工作。先看這個例子

上面解析到Properties窗體中的代碼,下面的代碼解釋它的工作原理

MathProgram builder = new MathProgram();
builder.ApplicationName= "Template Studio";
builder.SystemName= " ORM";
propertyGrid1.SelectedObject = builder;

ApplicationName和SystemName是Encapsulate Field的屬性名稱,并且帶有Browsable,Category元數據。

如果把這個類型放到另一個類型中去,代碼像這樣

Builder builder = new Builder();
builder.Category = "CNBLOGS";
builder.Math = new MathProgram();
builder.Math.ApplicationName= "Template Studio";
builder.Math.SystemName=" ORM";
propertyGrid1.SelectedObject = builder;

為了能在Properties窗體中設置值,要給它寫TypeConverter。一般像這樣的公共代碼就可以達到目的

public class CommonConverter : TypeConverter
{

?????? public override PropertyDescriptorCollection
?????????? GetProperties(ITypeDescriptorContext context,
??????????????? object value,
??????????????? Attribute[] filter)
?????? {
?????????? return TypeDescriptor.GetProperties(value, filter);
?????? }

?????? public override bool GetPropertiesSupported(
??????????????? ITypeDescriptorContext context)
?????? {
?????????? return true;
?????? }
}

上一節中應用到的ExpandConverter類型轉換器,它多了一項處理是可以把MathProgram顯示為字符串,比如從”ORM,Template Studio”中解析成MathProgram對象,這是TypeConverter的功勞。

?

動態編譯

模板的生成過程,就是生成一個以模板名字為類型名稱,以模板代碼為嵌入方法的過程。在代碼過程中,大部分的代碼都是在構造這個類型,以便于編譯器編譯成為程序集,再調用它的Render方法。方法代碼如下

Assembly assembly=CreateAssembly(sourceTemplate,language,parameters);

Type? type=assembly.GetType(“Template”);

InvokeMethod(type,”Render”);

把這三個過程細化,就是模板代碼生成的原理。在《模板代碼生成的原型》一節,再詳細講解動態編譯。

轉載于:https://www.cnblogs.com/JamesLi2015/archive/2011/09/05/2167000.html

總結

以上是生活随笔為你收集整理的ORM框架-工具-产品开发之四 开发代码生成器 Template Studio Development (一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。