当前位置: 移动技术网 > IT编程>开发语言>c# > C#如何通过T4自动生成代码详解

C#如何通过T4自动生成代码详解

2019年07月18日  | 移动技术网IT编程  | 我要评论

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; }
 }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网