用T4 Template生成代码

1   T4语法

T4的语法与ASP.NET的方式比较类似。主要包括指令、文本块、控制块。

1.1    指令

指令主要包括template, output, assembly, import, include等类型,用以告诉T4引擎如何编译和运行一个模板。这些指令相当于T4引擎的配置参数。

示例:

<#@ template debug="true" hostspecific="true" language="C#"  #>

告诉T4引擎控制块用c#编写;

<#@ output extension=".cs" #>

告诉T4引擎生成文件的后缀名是.cs;

<#@ assembly name="System.Core"#>

告诉T4引擎编译运行时引用System.Core程序集;

<#@ assembly name="$(SolutionDir)\Project.CodeGenerator\bin\Debug\MySql.Data.Dll"  #>

告诉T4引擎引用一个特定的位置上的程序集;

<#@ import namespace="System.Data.SqlClient"#>

告诉T4引擎编译运行时引用某个名称空间

<#@ include file="../Code/DBSchema.ttinclude"#>

告诉T4引擎编译运行时引用某个文件,类似于JS的引用

1.2    文本块

文本块, T4引擎会将文本块的内容直接复制到输出文件中。

1.3    控制块

控制块,主要用于控制文本的输出。在控制块可以写任意的C#代码。

1.4    示例Hello world

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>

Hello, <#Write("World");#>

2   工作原理

转载自:http://www.olegsych.com/2007/12/text-template-transformation-toolkit/

1>     Step1:编译模板,根据指令编译模板中的文本块和控制块,并生成一个继承于TextTransformation的类。

2>     Step2: T4引擎动态创建类的实例,并调用TransformText方法。

3  在T4中读取表结构

我们用T4时,主要是基于数据库或配置文件来生成各类的代码。所以如何有效地获取数据库的结构信息,是比较重要的。 之前看很多人直接把获取数据库的信息放在每一个模板中,在更换其它数据库时,又要重写模板。一个模板同时支持多个项目时,不同的项目数据库很有可能是不同的。

主要设计思想如下,简单地应用了简单工厂模式。通过DBSchemaFactory类根据不同数据库类型,获取数据库访问类的接口IDBSchema。最后返回相同的表结构信息。

DBSchema.ttinclude类:

根据不同的数据库,获取表结构信息。已包括SQLSERVER和MYSQL。

<#@ assembly name="System.Core"#>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.xml" #>
<#@ assembly name="$(SolutionDir)\bin\Debug\MySql.Data.Dll"  #>
<#@ import namespace="System"#>
<#@ import namespace="System.Collections.Generic"#>
<#@ import namespace="System.Data"#>
<#@ import namespace="System.Data.SqlClient"#>
<#@ import namespace="MySql.Data.MySqlClient"#>
<#+
#region Code
    public class DBSchemaFactory
    {
        static readonly string DatabaseType = "SqlServer";
        public static IDBSchema GetDBSchema()
        {
            IDBSchema dbSchema;
            switch (DatabaseType)
            {
                case "SqlServer":
                    {
                        dbSchema =new SqlServerSchema();
                        break;
                    }
                case "MySql":
                    {
                        dbSchema = new MySqlSchema();
                        break;
                    }
                default:
                    {
                        throw new ArgumentException("The input argument of DatabaseType is invalid!");
                    }
            }
            return dbSchema;
        }
    }

    public interface IDBSchema : IDisposable
    {
        List<string> GetTablesList();

        Table GetTableMetadata(string tableName);
    }

    public class SqlServerSchema : IDBSchema
    {
        public string ConnectionString = "Data Source=.;Initial Catalog=ProjectData;Persist Security Info=True;User ID=sa;Password=123456;";

        public SqlConnection conn;

        public SqlServerSchema()
        {
            conn = new SqlConnection(ConnectionString);
            conn.Open();
        }

        public List<string> GetTablesList()
        {
            DataTable dt = conn.GetSchema("Tables");
            List<string> list = new List<string>();
            foreach (DataRow row in dt.Rows)
            {
                list.Add(row["TABLE_NAME"].ToString());
            }
            return list;
        }

        public Table GetTableMetadata(string tableName)
        {
            string selectCmdText = string.Format("SELECT * FROM {0}", tableName); ;
            SqlCommand command = new SqlCommand(selectCmdText, conn);
            SqlDataAdapter ad = new SqlDataAdapter(command);
            System.Data.DataSet ds = new DataSet();
            ad.FillSchema(ds, SchemaType.Mapped, tableName);

            Table table = new Table(ds.Tables[0]);
            return table;
        }

        public void Dispose()
        {
            if (conn != null)
                conn.Close();
        }
    }

    public class MySqlSchema : IDBSchema
    {
        public string ConnectionString = "Server=localhost;Port=3306;Database=ProjectData;Uid=root;Pwd=;";

        public MySqlConnection conn;

        public MySqlSchema()
        {
            conn = new MySqlConnection(ConnectionString);
            conn.Open();
        }

        public List<string> GetTablesList()
        {
            DataTable dt = conn.GetSchema("Tables");
            List<string> list = new List<string>();
            foreach (DataRow row in dt.Rows)
            {
                list.Add(row["TABLE_NAME"].ToString());
            }
            return list;
        }

        public Table GetTableMetadata(string tableName)
        {
            string selectCmdText = string.Format("SELECT * FROM {0}", tableName); ;
            MySqlCommand command = new MySqlCommand(selectCmdText, conn);
            MySqlDataAdapter ad = new MySqlDataAdapter(command);
            System.Data.DataSet ds = new DataSet();
            ad.FillSchema(ds, SchemaType.Mapped, tableName);

            Table table = new Table(ds.Tables[0]);
            return table;
        }

        public void Dispose()
        {
            if (conn != null)
                conn.Close();
        }
    }

    public class Table
    {
        public Table(DataTable t)
        {
            this.PKs = this.GetPKList(t);
            this.Columns = this.GetColumnList(t);
            this.ColumnTypeNames = this.SetColumnNames();
        }

        public List<Column> PKs;

        public List<Column> Columns;

        public string ColumnTypeNames;
        public List<Column> GetPKList(DataTable dt)
        {
            List<Column> list = new List<Column>();
            Column c = null;
            if (dt.PrimaryKey.Length > 0)
            {
                list = new List<Column>();
                foreach (DataColumn dc in dt.PrimaryKey)
                {
                    c = new Column(dc);
                    list.Add(c);
                }
            }
            return list;
        }

        private List<Column> GetColumnList(DataTable dt)
        {
            List<Column> list = new List<Column>();
            Column c = null;
            foreach (DataColumn dc in dt.Columns)
            {
                c = new Column(dc);
                list.Add(c);
            }
            return list;
        }

        private string SetColumnNames()
        {
            List<string> list = new List<string>();
            foreach (Column c in this.Columns)
            {
                list.Add(string.Format("{0} {1}", c.TypeName, c.LowerColumnName));
            }
            return string.Join(",", list.ToArray());
        }
    }

    public class Column
    {
        DataColumn columnBase;

        public Column(DataColumn columnBase)
        {
            this.columnBase = columnBase;
        }

        public string ColumnName { get { return this.columnBase.ColumnName; } }

        public string MaxLength { get { return this.columnBase.MaxLength.ToString(); } }

        public string TypeName {
            get
            {
                string result = string.Empty;
                if (this.columnBase.DataType.Name == "Guid")//for mysql,因为对于MYSQL如果是CHAR(36),类型自动为Guid
                    result = "String";
                else
                    result = this.columnBase.DataType.Name;
                return result;
            }
        }

        public bool AllowDBNull { get { return this.columnBase.AllowDBNull; } }

        public string UpColumnName
        {
            get
            {
                return string.Format("{0}{1}", this.ColumnName[0].ToString().ToUpper(), this.ColumnName.Substring(1));
            }
        }

        public string LowerColumnName
        {
            get
            {
                return string.Format("{0}{1}", this.ColumnName[0].ToString().ToLower(), this.ColumnName.Substring(1));
            }
        }
    }

    public class GeneratorHelper
    {
        public static readonly string StringType = "String";
        public static readonly string DateTimeType = "DateTime";
        public static string GetQuesMarkByType(string typeName)
        {
            string result = typeName;
            if (typeName == DateTimeType)
            {
                result += "?";
            }
            return result;
        }
    }

    #endregion
#>

数据库结构的测试模板02 DBSchema.tt

输出数据库的所有表的结构信息

<#@ template debug="true" hostspecific="true" language="C#"  #>
<#@ output extension=".txt" #>
<#@ assembly name="System.Core"#>

<#@ import namespace="System"#>
<#@ import namespace="System.Collections.Generic"#>

<#@ include file="../Code/DBSchema.ttinclude"#>
<#
    var dbSchema=DBSchemaFactory.GetDBSchema();
    List<string> tableList=dbSchema.GetTablesList();
    foreach(string tableName in tableList)
    {
#>
<#= tableName #>
<#
        Table table=dbSchema.GetTableMetadata(tableName);
        foreach(Column c in table.PKs)
        {
#>
<#= c.ColumnName#>
<#        }
#>
ColumnName,TypeName,MaxLength,UpColumnName,LowerColumnName
<#
        foreach(Column c in table.Columns)
        {
#>
<#=c.ColumnName#>,<#=c.TypeName#>,<#=c.MaxLength#>,<#=c.UpColumnName#>,<#=c.LowerColumnName#>
<#
        }
#>
<#
    }
    dbSchema.Dispose();
#>

注:

1> 在DBSchema.ttinclude,所有的类都被包含在<#+ #>中,<#+ #>是一个类功能的控制块,其中可以定义任意的C#代码。这些类多是帮助类,所以又定义在一个可复用的模板中”.ttinclude”.

2> 在02 DBSchema.tt中有一行” <#@ include file="../Code/DBSchema.ttinclude"#>“,是指引用某个位置的文件,在这里指是引用一个可复用的模板。

4用T4生成实体

用T4生成一个代码的一个常用应用是生成实体类,下面是一个示例代码(此模板引用了DBSchema.ttinclude):

<#@ template debug="true" hostspecific="true" language="C#"  #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core"#>
<#@ import namespace="System"#>
<#@ import namespace="System.Collections.Generic"#>

<#@ include file="../Code/DBSchema.ttinclude"#>
<#
    var dbSchema=DBSchemaFactory.GetDBSchema();
    List<string> tableList=dbSchema.GetTablesList();
    foreach(string tableName in tableList)
    {
        Table table=dbSchema.GetTableMetadata(tableName);
#>
using System;
using System.Collections.Generic;
using System.Text;

namespace Project.Model
{
    [Serializable]
    public class <#=tableName#>
    {
        #region Constructor
        public <#=tableName#>() { }

        public <#=tableName#>(<#=table.ColumnTypeNames#>)
        {
<#
        foreach(Column c in table.Columns)
        {
#>
            this.<#=c.LowerColumnName#> = <#=c.LowerColumnName#>;
<#
        }
#>
        }
        #endregion

        #region Attributes
<#
        foreach(Column c in table.Columns)
        {
#>
        private <#=GeneratorHelper.GetQuesMarkByType(c.TypeName)#> <#=c.LowerColumnName#>;

        public <#=GeneratorHelper.GetQuesMarkByType(c.TypeName)#> <#=c.UpColumnName#>
        {
            get { return <#=c.LowerColumnName#>; }
            set { <#=c.LowerColumnName#> = value; }
        }
<#
        }
#>
        #endregion

        #region Validator
        public List<string> ErrorList = new List<string>();
        private bool Validator()
        {
            bool validatorResult = true;
<#
        foreach(Column c in table.Columns)
        {
            if(!c.AllowDBNull)
            {
                if(c.TypeName==GeneratorHelper.StringType)
                {
#>
            if (string.IsNullOrEmpty(this.<#=c.UpColumnName#>))
            {
                validatorResult = false;
                this.ErrorList.Add("The <#=c.UpColumnName#> should not be empty!");
            }
<#
                }
                if(c.TypeName==GeneratorHelper.DateTimeType)
                {
#>
            if (this.<#=c.UpColumnName#>==null)
            {
                validatorResult = false;
                this.ErrorList.Add("The <#=c.UpColumnName#> should not be empty!");
            }
<#
                }
            }
            if(c.TypeName==GeneratorHelper.StringType)
            {
#>
            if (this.<#=c.UpColumnName#> != null && <#=c.MaxLength#> < this.<#=c.UpColumnName#>.Length)
            {
                validatorResult = false;
                this.ErrorList.Add("The length of <#=c.UpColumnName#> should not be greater then <#=c.MaxLength#>!");
            }
<#
            }
        }
#>
            return validatorResult;
        }
        #endregion
    }
}
<#
    }
    dbSchema.Dispose();
#>

注:

1>     在这个模板中,<#= #>为表达式控制块

2>     除了表达式控制块,其它的代码块的开始<#和结束符#>最好是放在行首,这样一来容易分辨,二来最终输出的文本也是你想要的,不然文本块会乱掉。

5生成多个实体并分隔成多个文件

对于同时生成多个文件的模板可以直接下面的一个帮助类,这个帮助类可以帮助我们将一个文件分隔成多个文件(网上找的)。

分隔文件的帮助类:

<#@ assembly name="System.Core"#>

<#@ assembly name="EnvDTE"#>

<#@ import namespace="System.Collections.Generic"#>

<#@ import namespace="System.IO"#>

<#@ import namespace="System.Text"#>

<#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>

<#+

// T4 Template Block manager for handling multiple file outputs more easily.
// Copyright (c) Microsoft Corporation.  All rights reserved.
// This source code is made available under the terms of the Microsoft Public License (MS-PL)

// Manager class records the various blocks so it can split them up
class Manager
{
    public struct Block {
        public String Name;
        public int Start, Length;
    }

    public List<Block> blocks = new List<Block>();
    public Block currentBlock;
    public Block footerBlock = new Block();
    public Block headerBlock = new Block();
    public ITextTemplatingEngineHost host;
    public ManagementStrategy strategy;
    public StringBuilder template;
    public String OutputPath { get; set; }

    public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
        this.host = host;
        this.template = template;
        OutputPath = String.Empty;
        strategy = ManagementStrategy.Create(host);
    }

    public void StartBlock(String name) {
        currentBlock = new Block { Name = name, Start = template.Length };
    }

    public void StartFooter() {
        footerBlock.Start = template.Length;
    }

    public void EndFooter() {
        footerBlock.Length = template.Length - footerBlock.Start;
    }

    public void StartHeader() {
        headerBlock.Start = template.Length;
    }

    public void EndHeader() {
        headerBlock.Length = template.Length - headerBlock.Start;
    }    

    public void EndBlock() {
        currentBlock.Length = template.Length - currentBlock.Start;
        blocks.Add(currentBlock);
    }

    public void Process(bool split) {
        String header = template.ToString(headerBlock.Start, headerBlock.Length);
        String footer = template.ToString(footerBlock.Start, footerBlock.Length);
        blocks.Reverse();
        foreach(Block block in blocks) {
            String fileName = Path.Combine(OutputPath, block.Name);
            if (split) {
                String content = header + template.ToString(block.Start, block.Length) + footer;
                strategy.CreateFile(fileName, content);
                template.Remove(block.Start, block.Length);
            } else {
                strategy.DeleteFile(fileName);
            }
        }
    }
}

class ManagementStrategy
{
    internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
        return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);
    }

    internal ManagementStrategy(ITextTemplatingEngineHost host) { }

    internal virtual void CreateFile(String fileName, String content) {
        File.WriteAllText(fileName, content);
    }

    internal virtual void DeleteFile(String fileName) {
        if (File.Exists(fileName))
            File.Delete(fileName);
    }
}

class VSManagementStrategy : ManagementStrategy
{
    private EnvDTE.ProjectItem templateProjectItem;

    internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
        IServiceProvider hostServiceProvider = (IServiceProvider)host;
        if (hostServiceProvider == null)
            throw new ArgumentNullException("Could not obtain hostServiceProvider");

        EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
        if (dte == null)
            throw new ArgumentNullException("Could not obtain DTE from host");

        templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
    }

    internal override void CreateFile(String fileName, String content) {
        base.CreateFile(fileName, content);
        ((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);
    }

    internal override void DeleteFile(String fileName) {
        ((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);
    }

    private void FindAndDeleteFile(String fileName) {
        foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
            if (projectItem.get_FileNames(0) == fileName) {
                projectItem.Delete();
                return;
            }
        }
    }
}#>

示例模板:

生成某个数据库下面所有的表的实体,并放在不同的文件里。

<#@ template debug="true" hostspecific="true" language="C#"  #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core"#>
<#@ import namespace="System"#>
<#@ import namespace="System.Collections.Generic"#>
<#@ include file="../Code/DBSchema.ttinclude"#>
<#@ include file="../Code/MultiDocument.ttinclude"#>
<# var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = Path.GetDirectoryName(Host.TemplateFile)}; #>
<#
    var dbSchema=DBSchemaFactory.GetDBSchema();
    List<string> tableList=dbSchema.GetTablesList();
    foreach(string tableName in tableList)
    {
        manager.StartBlock(tableName+".cs");
        Table table=dbSchema.GetTableMetadata(tableName);
#>
using System;
using System.Collections.Generic;
using System.Text;

namespace Project.Model
{
    [Serializable]
    public class <#=tableName#>
    {
        #region Constructor
        public <#=tableName#>() { }

        public <#=tableName#>(<#=table.ColumnTypeNames#>)
        {
<#
        foreach(Column c in table.Columns)
        {
#>
            this.<#=c.LowerColumnName#> = <#=c.LowerColumnName#>;
<#
        }
#>
        }
        #endregion

        #region Attributes
<#
        foreach(Column c in table.Columns)
        {
#>
        private <#=GeneratorHelper.GetQuesMarkByType(c.TypeName)#> <#=c.LowerColumnName#>;

        public <#=GeneratorHelper.GetQuesMarkByType(c.TypeName)#> <#=c.UpColumnName#>
        {
            get { return <#=c.LowerColumnName#>; }
            set { <#=c.LowerColumnName#> = value; }
        }
<#
        }
#>
        #endregion

        #region Validator
        public List<string> ErrorList = new List<string>();
        private bool Validator()
        {
            bool validatorResult = true;
<#
        foreach(Column c in table.Columns)
        {
            if(!c.AllowDBNull)
            {
                if(c.TypeName==GeneratorHelper.StringType)
                {
#>
            if (string.IsNullOrEmpty(this.<#=c.UpColumnName#>))
            {
                validatorResult = false;
                this.ErrorList.Add("The <#=c.UpColumnName#> should not be empty!");
            }
<#
                }
                if(c.TypeName==GeneratorHelper.DateTimeType)
                {
#>
            if (this.<#=c.UpColumnName#>==null)
            {
                validatorResult = false;
                this.ErrorList.Add("The <#=c.UpColumnName#> should not be empty!");
            }
<#
                }
            }
            if(c.TypeName==GeneratorHelper.StringType)
            {
#>
            if (this.<#=c.UpColumnName#> != null && <#=c.MaxLength#> < this.<#=c.UpColumnName#>.Length)
            {
                validatorResult = false;
                this.ErrorList.Add("The length of <#=c.UpColumnName#> should not be greater then <#=c.MaxLength#>!");
            }
<#
            }
        }
#>
            return validatorResult;
        }
        #endregion
    }
}
<#
        manager.EndBlock();
    }
    dbSchema.Dispose();

    manager.Process(true);
#>

6 其它

T4的编辑工具下载地址http://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html

VS默认的编辑工具无高亮,无提示,错误不易定位。 没这个工具,真心不想写任何T4代码。

所有示例代码: CodeGenerator.zip

用T4 Template生成代码

时间: 2024-11-16 12:05:49

用T4 Template生成代码的相关文章

使用T4模板生成代码的学习

之前做项目使用的都是Db First,直接在项目中添加Entity Framework,使用T4模板(T4模板引擎之基础入门)生成DAL BLL层等(T4模板是一个同事给的,也没有仔细研究,代码如下:) <#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="EF.Utility.CS.ttinclude"

[转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:HelloWorld.cs (二) 多文件生成 四.生成数据层实体相关相似代码 (一) 生成准备 (二) 生成实体相关相似代码 生成实体映射配置类 生成实体仓储接口 生成实体仓储实现 五.源码获取 系列导航 一.前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少

T4模板:MVC中用T4模板快速生成代码

T4模板快速生成代码: 以快速生Dal文件为例,下面为T4模板文件的内容 <#@ template debug="false" hostspecific="true" language="C#" #> <#@ include file="EF.Utility.CS.ttinclude"#> <#@ output extension=".cs" #> <# CodeG

利用T4模板生成ASP.NET Core控制器的构造函数和参数

前言 在ASP.NET Core中引入了DI,并且通过构造函数注入参数,控制器中会大量使用DI注入各种的配置参数,如果配置注入的参数比较多,而且各个控制器需要的配置参数都基本一样的话,那么不断重复的复制黏贴代码提供相应的构造函数,效率低效也,因此使用T4模板生成控制器的构造函数 ,这也得益于C#对分部类(partial)的支持. T4模板生成控制器构造函数 图中CtrlTemplate.tt为模板文件,CtrlNames.txt为需要使用T4生成代码的控制器名称文件,CtrlTemplate.c

使用T4模板生成不同部署环境下的配置文件

在开发企业级应用的时候,通常会有不同的开发环境,比如有开发环境,测试环境,正式环境,生产环境等.在一份代码部署到不同环境的时候,不同环境的配置文件可能需要根据目标环境不同而不同.比如在开发环境中,数据库使用的是开发环境的数据库,消息队列也使用的部署在开发机上的消息队列,传统的方式是,由发布或者配置管理员来维护这些不同环境的配置文件.通常,手工的针对不同的环境去修改配置文件容易产生错误. 有很多种不同的方式来针对不同的部署环境生成配置,最笨的方法就是可以维护几套不同的配置文件,然后在编译事件中根据

七色花基本权限系统(5)- 实体配置的使用和利用T4自动生成实体配置

在前面的章节里,用户表的结构非常简单,没有控制如何映射到数据库.通常,需要对字段的长度.是否可为空甚至特定数据类型进行设置,因为EntityFramework的默认映射规则相对而言比较简单和通用.在这篇日志里,将演示如何对数据实体进行映射配置,并利用T4模板自动创建映射配置类文件. 配置方式 EntityFramework的实体映射配置有2种. 第一种是直接在实体类中以特性的方式进行控制,这些特性有部分是EF实现的,也有部分是非EF实现的.也就是说,在数据实体层不引用EF的情况下,只能使用不全的

使用 Velocity 模板引擎快速生成代码

原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-velocity1/ Velocity 是一个基于 Java 的模板引擎,它允许任何人仅仅简单的使用模板语言来引用由 Java 代码定义的对象,从而实现界面和 Java 代码的分离,使得界面设计人员可以和 Java 程序开发人员同步开发一个遵循 MVC 架构的 web 站点.但是在实际应用过程中,Velocity 又不仅仅被用在了 MVC 的架构中. Velocity 模板引擎介绍 在现今的软

java自动生成代码

看到这个标题,如果你以为真的可以完全自动生成,那你就太Naive啦 我这里想介绍的是,利用模板生成我们需要的代码 一.模板 首先来说说模板,常见的java模板有:FreeMarker.Velocity.Jamon.JByte等等. 不熟悉的可以百度下,其实我了解也不多,哈哈. 二.原理 其实就是利用模板,填充数据,得到我们需要的代码.即:输出=模板+数据 三.实例 实例利用FreeMarker来做的,所以你需要先导入freemarker的jar包 假设我们需要自动生成一个java bean,那么

json 对c++类的序列化(自动生成代码)

[动机] 之前写网络协议的时候,使用的是google protobuf,protobuf不但在性能和扩展性上有很好的优势,protoc自动生成c++类代码的工具,这点确实给程序员带来了很多便利. 做后面一项目使用的json格式来传输,然后就萌生了实现像protoc这样的工具,根据json文件来生成c++类代码,并且生成序列化代码,这样在写网络的时候就无需把jsonvalue序列化散落在各处. [思路] 之前写object-c的时候,如果你要对类的序列化,你必须实现NSCoding协议(接口),