C#如何通过T4自动生成代码详解
程序员文章站
2023-12-09 18:54:15
t4简介
t4(text template transformation toolkit)在 visual studio 中,“t4 文本模板”是由一些文本块和控制逻...
t4简介
t4(text template transformation toolkit)在 visual studio 中,“t4 文本模板”是由一些文本块和控制逻辑组成的混合模板,它可以生成文本文件。 在 visual c# 或 visual basic 中,控制逻辑编写为程序代码的片段。生成的文件可以是任何类型的文本,例如网页、资源文件或任何语言的程序源代码。
t4 文本模板有两种类型:
1、运行时模板
可在应用程序中执行运行时 t4 文本模板(“预处理过的”模板)以便生成文本字符串(通常作为其输出的一部分)。
若要创建运行时模板,请向您的项目中添加“已预处理的文本模板”文件。
另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“texttemplatingfilepreprocessor”。
2、设计时模板
在 visual studio 中执行设计时 t4 文本模板,以便定义应用程序的部分源代码和其他资源。
通常,您可以使用读取单个输入文件或数据库中的数据的多个模板,并生成一些 .cs、.vb 或其他源文件。
每个模板都生成一个文件。 在 visual studio 或 msbuild 内执行它们。
若要创建设计时模板,请向您的项目中添加“文本模板”文件。 另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“texttemplatingfilegenerator”。
通过t4模板生成代码,运行时实现
关键代码段:host
using microsoft.visualstudio.texttemplating; using system; using system.codedom.compiler; using system.collections.generic; using system.io; using system.linq; using system.text; using system.threading.tasks; namespace codegenerate.enginehost { public class texttemplatingenginehost : itexttemplatingenginehost, itexttemplatingsessionhost { public list<string> localdlls { get; set; } public list<string> namespaces { get; set; } /// <summary> /// 模板文件 /// </summary> public string templatefile { get; set; } /// <summary> /// 文件扩展名 /// </summary> public string fileextension { get; set; } /// <summary> /// 文件扩展名 /// </summary> public encoding fileencoding { get; set; } /// <summary> /// 错误信息 /// </summary> public compilererrorcollection errors { get; set; } public ilist<string> standardassemblyreferences { get { localdlls.add(typeof(system.uri).assembly.location); return localdlls; } } public ilist<string> standardimports { get { namespaces.add("system"); return namespaces; } } /// <summary> /// 参数传递 /// </summary> public itexttemplatingsession session { get; set; } public bool loadincludetext(string requestfilename, out string content, out string location) { content = system.string.empty; location = system.string.empty; if (file.exists(requestfilename)) { content = file.readalltext(requestfilename); return true; } else { return false; } } public object gethostoption(string optionname) { object returnobject; switch (optionname) { case "cacheassemblies": returnobject = true; break; default: returnobject = null; break; } return returnobject; } public string resolveassemblyreference(string assemblyreference) { if (file.exists(assemblyreference)) { return assemblyreference; } string candidate = path.combine(path.getdirectoryname(this.templatefile), assemblyreference); if (file.exists(candidate)) { return candidate; } return ""; } public type resolvedirectiveprocessor(string processorname) { if (string.compare(processorname, "xyz", stringcomparison.ordinalignorecase) == 0) { //return typeof(); } throw new exception("directive processor not found"); } public string resolvepath(string filename) { if (filename == null) { throw new argumentnullexception("the file name cannot be null"); } if (file.exists(filename)) { return filename; } string candidate = path.combine(path.getdirectoryname(this.templatefile), filename); if (file.exists(candidate)) { return candidate; } return filename; } public string resolveparametervalue(string directiveid, string processorname, string parametername) { if (directiveid == null) { throw new argumentnullexception("the directiveid cannot be null"); } if (processorname == null) { throw new argumentnullexception("the processorname cannot be null"); } if (parametername == null) { throw new argumentnullexception("the parametername cannot be null"); } return string.empty; } public void setfileextension(string extension) { fileextension = extension; } public void setoutputencoding(system.text.encoding encoding, bool fromoutputdirective) { fileencoding = encoding; } public void logerrors(compilererrorcollection errors) { errors = errors; } public appdomain providetemplatingappdomain(string content) { return appdomain.createdomain("generation app domain"); } public itexttemplatingsession createsession() { return this.session; } } }
session
using microsoft.visualstudio.texttemplating; using system; using system.collections; using system.collections.generic; using system.linq; using system.runtime.serialization; using system.text; using system.threading.tasks; namespace codegenerate.enginehost { [serializable] public class texttemplatingsession : dictionary<string, object>, itexttemplatingsession, iserializable { public guid id { get;private set; } public texttemplatingsession() : this(guid.newguid()) { } public texttemplatingsession(guid id) { this.id = id; } public override int gethashcode() { return id.gethashcode(); } public texttemplatingsession(serializationinfo info, streamingcontext context) : base(info, context) { id = (guid)info.getvalue("id", typeof(guid)); } void iserializable.getobjectdata(serializationinfo info, streamingcontext context) { base.getobjectdata(info, context); info.addvalue("id", id); } public override bool equals(object obj) { var o = obj as texttemplatingsession; return o != null && o.equals(this); } public bool equals(itexttemplatingsession other) { return other != null && other.id == this.id; } public bool equals(guid other) { return other.equals(id); } } }
入口
string templatefilename = "template/test.tt"; texttemplatingenginehost host = new texttemplatingenginehost(); engine engine = new engine(); //引入本地dll host.localdlls = new list<string>() { appdomain.currentdomain.basedirectory.tostring() + "params.dll" }; //引入命名空间 host.namespaces = new list<string>() { "params" }; //模板文件 host.templatefile = templatefilename; //设置输出文件的编码格式 host.setoutputencoding(system.text.encoding.utf8, false); //通过session将参数传递到模板 enginehost.texttemplatingsession keyvaluepairs = new enginehost.texttemplatingsession(); testtype t = new testtype() { name = "666666666666" }; keyvaluepairs.add("test", t); host.session = keyvaluepairs; //模板 string input = file.readalltext(templatefilename); //执行代码生成 string output = engine.processtemplate(input, host); //设置文件的输出路径和文件扩展名 ,,根据模板中的设置定义 string outputfilename = string.concat( appdomain.currentdomain.basedirectory.tostring(), "output/", path.getfilenamewithoutextension(templatefilename), host.fileextension); //将生成的文件写入到新位置 file.writealltext(outputfilename, output, host.fileencoding); if (host.errors.haserrors) { foreach (compilererror error in host.errors) { messagebox.show(error.tostring()); } }
tt文件
<#@ template debug="false" hostspecific="false" language="c#" #> <#@ import namespace="system.collections.generic" #> <#@ assembly name="params.dll" #> <#@ import namespace="params" #> <#@ parameter type="params.testtype" name="test" #> <#@ output extension=".cs" #> <# if(test!=null&&test.name!=null){#> <#=test.name #> <# } #>
自定义参数
[serializable] public class testtype { public string name { get; set; } }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。