在开发过程种,很多时候我们会写很多相似度很高的代码,书写这些代码是有规律的,比如我们会根据数据表生成实体类,就像EF那样,会从表中自动生成实体类,如果我们写一个应用程序,读取数据库,然后生成一个.cs类文件,这个相对简单,如果在VS中能解决这个问题,不用单跑一个执行程序就happy了,那T4就是来干这件事的。T4Text Template Transformation Toolkit全称,不作更多的解释,VS中的T4详见https://msdn.microsoft.com/zh-cn/library/bb126445.aspx

简单看一个例子,就是把数据的表生成对应的实体类,在项目中创建一个“运行时文本模版”,扩展名是.tt,其实.tt中的代码是标准的C#代码,并键时.tt可以在设计时生成.cs文件,也可以运行时生成,本例是设计时生成,代码如下:

<#@ template debug="false" hostspecific="true" language="C#" #><#@ assembly name="System.Core" #><#@ assembly name="System.Data" #><#@ assembly name="System.Configuration" #><#@ assembly name="System.Xml" #><#@ import namespace="System.Linq" #><#@ import namespace="System.Text" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Configuration" #><#@ import namespace="System.Xml" #><#@ output extension=".txt" #>
 
 <#//数据库连接字符串
var constr="server=.;database=testdb;uid=sa;pwd=gsw123;";
//遍历实体类并生成
foreach (var clas in BuildClass(constr))
{
     WriteFile(clas.Key,BuildContent(clas.Value));
	 AddFileToProject(clas.Key);
}#>生成实体类成功! 
 
<#+ 
//组装实体类和它的命名空间
string BuildContent(string content)
{
return @"
/*****************************
*作者:桂素伟                 
*时间:"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+@"             
*说明:按照数据库表自动生成的类 
******************************/
using System;
using System.Text;
namespace "+Host.ResolveAssemblyReference("$(ProjectName)")+@"
{
"+
content
+@"
}
";
 
}
//把生成的实体类文件添加到当前项目中
public void AddFileToProject(string className)
{
     //获取当前项目的名称
	 var proName=Host.ResolveAssemblyReference("$(ProjectName)")+".csproj";
	 XmlDocument xmlDoc = new XmlDocument();
     xmlDoc.LoadXml(System.IO.File.ReadAllText(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+proName,Encoding.Default));
     XmlNode root = xmlDoc.DocumentElement;
	 if( !root.InnerXml.Contains(@"Include=""" + className + @".cs"""))
	 {    
	    root.InnerXml += @"<ItemGroup><Compile Include="""+className+@".cs""></Compile></ItemGroup>";
	    xmlDoc.Save(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+proName);
	 }
 
}
//生成实体类文件
public void WriteFile(string className,string content)
{
	 var writer = new System.IO.StreamWriter(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+className + ".cs", false, Encoding.Default);
     writer.Write(content);
     writer.Flush();
     writer.Close();
 
}
//从数据库获取实体类名和实体类源码
public  Dictionary<string,string> BuildClass(string constr)
{
          
            using (var con = new System.Data.SqlClient.SqlConnection(constr))
            {
                var cmd = new System.Data.SqlClient.SqlCommand();
                cmd.CommandText = "select name from sys.tables WHERE name!='sysdiagrams' AND name!='__MigrationHistory'";
                cmd.Connection = con;
                con.Open();
                var dr = cmd.ExecuteReader();
                var dt = new DataTable();
                dt.Load(dr);
                dr.Close();
 
                var dic =new Dictionary<string, string>();
                foreach (DataRow row in dt.Rows)
                {
                    cmd.CommandText = string.Format(@"select COLUMN_NAME,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,IS_NULLABLE
 from information_schema.columns WHERE TABLE_NAME = '{0}'", row["name"].ToString());
                    var fielddr = cmd.ExecuteReader();
                    var fieldTable = new DataTable();
                    fieldTable.Load(fielddr);
                    fielddr.Close();
                    dic.Add(row["name"].ToString(), CreateClass(row["name"].ToString(), fieldTable));
                }
                return dic;
            }
 
        }
  
	
        public string CreateClass(string className, DataTable fields)
        {
            var csBuilder = new StringBuilder("\r\n");
            csBuilder.AppendLine(string.Format(@"	public class {0}", className));
            csBuilder.AppendLine(@"	{");
            foreach (DataRow row in fields.Rows)
            {
                csBuilder.AppendLine(CreateProperty(row));
				
            }
            csBuilder.AppendLine(@"   }");
            return csBuilder.ToString();
        }
//生成属性
public string CreateProperty(DataRow row)
{
    var dic = new Dictionary<string, string>();
    dic.Add("nvarchar", "string");
    dic.Add("varchar", "string");
    dic.Add("char", "string");
    dic.Add("text", "string");
    dic.Add("int", "string");
    dic.Add("money", "decimal");
    dic.Add("float", "float");
    dic.Add("bit", "bool");
    var csBuilder = new StringBuilder();
    csBuilder.AppendLine(string.Format(@"      public {0} {1}", dic[row["DATA_TYPE"].ToString().ToLower()], row["COLUMN_NAME"].ToString()));
    csBuilder.AppendLine(@"      {");
    csBuilder.AppendLine(string.Format(@"         get;"));
    csBuilder.AppendLine(string.Format(@"         set;"));
    csBuilder.AppendLine(@"      }");
 
    return csBuilder.ToString();
} 
		#>