.NET Core 运行时T4模板使用,T4生成代码
背景
利用T4模板自动生成代码
在.NET Framework中我们可以这样实现
添加引用:
Microsoft.VisualStudio.TextTemplating.10.0
Microsoft.VisualStudio.TextTemplating.Interfaces.10.0
VS2017以上,引用是
Microsoft.VisualStudio.TextTemplating.Interfaces.11.0
Microsoft.VisualStudio.TextTemplating.15.0
利用T4模板生成字符串的代码
C# 全选
public static string CreateEntityClass(EntityModel classInfo)
{
string templatePath = Common.T4Template_Entity;
return CreateClass(classInfo, templatePath);
}
public static string CreateClass(object classInfo, string templatePath)
{
if (!File.Exists(templatePath))
{
MessageBox.Show("未找到Entity.tt,请修改配置文件!\r\n" + templatePath);
return null;
}
CustomTextTemplatingEngineHost host = new CustomTextTemplatingEngineHost();
host.TemplateFileValue = templatePath;
string input = File.ReadAllText(templatePath);
host.Session = new TextTemplatingSession();
host.Session.Add("entity", classInfo);
string output = new Engine().ProcessTemplate(input, host);
StringBuilder errorWarn = new StringBuilder();
foreach (CompilerError error in host.Errors)
{
errorWarn.Append(error.Line).Append(":").AppendLine(error.ErrorText);
}
if (!File.Exists("Error.log"))
{
using ( var f=File.Create("Error.log"))
{
}
}
File.WriteAllText("Error.log", errorWarn.ToString());
return output;
}
CustomTextTemplatingEngineHost.cs
C# 全选
public class CustomTextTemplatingEngineHost : ITextTemplatingEngineHost, ITextTemplatingSessionHost
{
#region ITextTemplatingEngineHost
internal string TemplateFileValue;
public string TemplateFile
{
get { return TemplateFileValue; }
}
private string fileExtensionValue = ".txt";
public string FileExtension
{
get { return fileExtensionValue; }
}
private Encoding fileEncodingValue = Encoding.UTF8;
public Encoding FileEncoding
{
get { return fileEncodingValue; }
}
private CompilerErrorCollection errorsValue;
public CompilerErrorCollection Errors
{
get { return errorsValue; }
}
public IList<string> StandardAssemblyReferences
{
get
{
return new string[]
{
typeof(System.Uri).Assembly.Location
};
}
}
public IList<string> StandardImports
{
get
{
return new string[]
{
"System"
};
}
}
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)
{
fileExtensionValue = extension;
}
public void SetOutputEncoding(System.Text.Encoding encoding, bool fromOutputDirective)
{
fileEncodingValue = encoding;
}
public void LogErrors(CompilerErrorCollection errors)
{
errorsValue = errors;
}
public AppDomain ProvideTemplatingAppDomain(string content)
{
return AppDomain.CreateDomain("Generation App Domain");
}
#endregion
#region ITextTemplatingSessionHost
public ITextTemplatingSession CreateSession()
{
return Session;
}
public ITextTemplatingSession Session
{
get;
set;
}
#endregion
}
在.NET Core中使用
.NET Core中无法引用 Microsoft.VisualStudio.TextTemplating.15.0 (不支持.NETCore版本)
参考:
https://github.com/dotnet/runtime/issues/45048#issuecomment-731563466
Founds a fork wich could work: https://github.com/SubSonic-Core/SubSonic.Core.TextTemplating
see: mono/t4#89
在.NET Core中T4模板的使用可以用 SubSonic.Core.TextTemplating
使用方法
项目中添加 SubSonic.Core.TextTemplation 的Nuget引用
测试代码:
C# 全选
using Microsoft.AspNetCore.Mvc;
using Mono.TextTemplating;
using Mono.VisualStudio.TextTemplating;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace YESCMS.Controllers
{
public class testController : ControllerBase
{
public IActionResult T4()
{
string input =
"<#@ template language=\"C#\" #>\r\n" +
"<# foreach(string str in new string[]{\"a\",\"b\",\"c\",\"d\",\"e\"})" +
"{ #>" +
" [<#= str#>]" +
"<#" +
"} #>";
var gen = new TemplateGenerator();
string tmp = null;
string tmp2 = null;
bool b = gen.ProcessTemplate(null, input, ref tmp, out tmp2);
return Content(tmp2);
}
string Preprocess(string input, DummyHost host)
{
string className = "PreprocessedTemplate";
string classNamespace = "Templating";
string language = null;
string[] references = null;
TemplatingEngine engine = new TemplatingEngine();
string output = engine.PreprocessTemplate(input, host, className, classNamespace, out language, out references);
ReportErrors(host.Errors.ToCompilerErrorCollection());
if (output != null)
{
return TemplatingEngineHelper.CleanCodeDom(output, "\n");
}
return null;
}
void ReportErrors(CompilerErrorCollection errors)
{
foreach (CompilerError error in errors)
{
Console.WriteLine(error.ErrorText);
}
}
}
public static class TemplatingEngineHelper
{
/// <summary>
/// Cleans CodeDOM generated code so that Windows/Mac and Mono/.NET output can be compared.
/// </summary>
public static string CleanCodeDom(string input, string newLine)
{
using (var writer = new StringWriter())
{
using (var reader = new StringReader(input))
{
bool afterLineDirective = true;
bool stripHeader = true;
string line;
while ((line = reader.ReadLine()) != null)
{
if (stripHeader)
{
if (line.StartsWith("//", StringComparison.Ordinal) || StringUtil.IsNullOrWhiteSpace(line))
continue;
stripHeader = false;
}
if (afterLineDirective)
{
if (StringUtil.IsNullOrWhiteSpace(line))
continue;
afterLineDirective = false;
}
if (line.Contains("#line"))
{
afterLineDirective = true;
}
writer.Write(line);
writer.Write(newLine);
}
}
return writer.ToString();
}
}
}
internal static class StringUtil
{
public static bool IsNullOrWhiteSpace(String value)
{
if (value == null) return true;
for (int i = 0; i < value.Length; i++)
{
if (!char.IsWhiteSpace(value[i])) return false;
}
return true;
}
public static TType GetValue<TType>(this PropertyInfo property, object @object, object[] index)
{
if (property.GetValue(@object, index) is TType success)
{
return success;
}
return default;
}
public static bool TryParse<TEnum>(this string value, out TEnum @enum)
where TEnum : struct
{
#if NET35
if (Enum.Parse (typeof (TEnum), value) is TEnum success) {
@enum = success;
return true;
}
@enum = default;
return false;
#else
return Enum.TryParse(value, out @enum);
#endif
}
}
public class DummyHost : ITextTemplatingEngineHost
{
public readonly Dictionary<string, string> Locations = new Dictionary<string, string>();
public readonly Dictionary<string, string> Contents = new Dictionary<string, string>();
public readonly Dictionary<string, object> HostOptions = new Dictionary<string, object>();
List<string> standardAssemblyReferences = new List<string>(new[] { typeof(TemplatingEngine).Assembly.Location });
List<string> standardImports = new List<string>();
public readonly TemplateErrorCollection Errors = new TemplateErrorCollection();
public readonly Dictionary<string, Type> DirectiveProcessors = new Dictionary<string, Type>();
public readonly Dictionary<string, string> Parameters = new Dictionary<string, string>();
public virtual object GetHostOption(string optionName)
{
object o;
HostOptions.TryGetValue(optionName, out o);
return o;
}
public virtual bool LoadIncludeText(string requestFileName, out string content, out string location)
{
content = null;
return Locations.TryGetValue(requestFileName, out location)
&& Contents.TryGetValue(requestFileName, out content);
}
public virtual void LogErrors(TemplateErrorCollection errors)
{
Errors.AddRange(errors);
}
public virtual AppDomain ProvideTemplatingAppDomain(string content)
{
return null;
}
public virtual string ResolveAssemblyReference(string assemblyReference)
{
throw new System.NotImplementedException();
}
public virtual Type ResolveDirectiveProcessor(string processorName)
{
Type t;
DirectiveProcessors.TryGetValue(processorName, out t);
return t;
}
public virtual string ResolveParameterValue(string directiveId, string processorName, string parameterName)
{
return Parameters[parameterName];
}
public virtual string ResolvePath(string path)
{
throw new System.NotImplementedException();
}
string extension;
public virtual void SetFileExtension(string extension)
{
this.extension = extension;
}
public virtual void SetOutputEncoding(System.Text.Encoding encoding, bool fromOutputDirective)
{
}
public virtual IList<string> StandardAssemblyReferences
{
get { return standardAssemblyReferences; }
}
public virtual IList<string> StandardImports
{
get { return standardImports; }
}
public virtual string TemplateFile
{
get; set;
}
}
}
运行测试:
参考
SubSonic.Core.TextTemplating GitHub地址:https://github.com/SubSonic-Core/SubSonic.Core.TextTemplating
版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
post 管理员