我正在为VS进行扩展。它应该通过TT模板映射数据库对象。扩展的用户可以制作模板。唯一的事情是,必须继承抽象模板,whitch是扩展的一部分。我在Microsoft文档中找到了一个建议,以这种方式在VS扩展中调用转换:Invoking Text Transformation in a VS Extension对于虚拟模板,如下所示,效果很好:
<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#
Generate(new List<string> {"AAA","BBB","CCC"}, "666");
#>
<#+
public void Generate(List<string> inputList, string tableName)
{
#>
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.Serialization;
namespace BBB
public class <#= tableName #>
{
<#+
foreach(var t in inputList)
{
#>
/// <summary>
/// <#= t #>
/// </summary>
<#+
}
#>
}
<#+
}
#>
和代码:
Generate("..\\..\\Templates\\TextTemplate.tt");
public void Generate(string filePath)
{
IServiceProvider serviceProvider = ServiceProvider;
ITextTemplating t4 = serviceProvider.GetService(typeof(STextTemplating)) as ITextTemplating;
T4Callback cb = new T4Callback();
string result = t4.ProcessTemplate(filePath, File.ReadAllText(filePath), cb);
string resultFileName = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)) + "_gen" + cb.fileExtension;
File.WriteAllText(resultFileName, result, cb.outputEncoding);
}
public class T4Callback : ITextTemplatingCallback
{
public List<string> errorMessages = new List<string>();
public string fileExtension = ".cs";
public Encoding outputEncoding = Encoding.UTF8;
public void ErrorCallback(bool warning, string message, int line, int column)
{ errorMessages.Add(message); }
public void SetFileExtension(string extension)
{ fileExtension = extension; }
public void SetOutputEncoding(Encoding encoding, bool fromOutputDirective)
{ outputEncoding = encoding; }
}
但是它不适用于抽象模板。如果我有抽象模板:
<#@ template language="C#" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ parameter type="System.String" name="FakeIn" #>
<#
this.PushIndent(" ");
//Generate method
Generate(InputData);
//Save method
SaveOutput(OutputFileName);
this.PopIndent();
#>
<#+
#region Properties
public string OutputFileName { get; set; }
public InPutClass InputData { get; set; }
#endregion
#region Override method
protected virtual void Generate(InPutClass input) { }
#endregion
#region Non-Override method
protected void SaveOutput(string outputFileName)
{
string outputFilePath = Path.Combine(outputFileName);
File.WriteAllText(outputFilePath, this.GenerationEnvironment.ToString());
this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length);
}
#endregion
#region Data classes
public class InPutClass
{
public List<string> InputList { get; set; }
public string InputTableName { get; set; }
}
#endregion
#>
并得出这样的一个:
<#@ template language="C#" inherits="AbstractTemplate" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#
InputData = new InPutClass{ InputList = new List<string>{"AAA","BBB","CCC"}, InputTableName = "abc" };
OutputFileName = "..\\..\\Templates\\file2.cs";
base.TransformText();
#>
<#+
protected override void Generate(InPutClass input)
{
#>
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.Serialization;
using ABEL.CORE.TypeComponents;
using ABEL.DAL.Attributes;
using Protos.Data;
namespace BBB
public class <#= input.InputTableName #>
{
<#+
foreach(var t in input.InputList)
{
#>
/// <summary>
/// <#= t #>
/// </summary>
<#+
}
#>
}
<#+
}
#>
如果我调用方法“生成结果”为:
ErrorGeneratingOutput
所以对我来说,模板对您自己一无所知。因为当我将它们都作为解决方案的一部分时,只需调用经典模板template.TransformText();即可。一切都好。
我还尝试了PreprocessingTemplate的某种组合,例如:
GenerateAbstract("\\..\\..\\Templates2\\DerivedTemplate2.tt");
public void GenerateAbstract(string filePath)
{
IServiceProvider serviceProvider = ServiceProvider;
ITextTemplating t4 = serviceProvider.GetService(typeof(STextTemplating)) as ITextTemplating;
T4Callback cb = new T4Callback();
string[] reference;
string abstractTemplatePath = "..\\..\\Templates2\\AbstractTemplate.tt";
string abstractTemplatePreprocessing = t4.PreprocessTemplate(abstractTemplatePath, File.ReadAllText(abstractTemplatePath), cb, "AbstractTemplate", "AbstractTemplating.Templates2", out reference);
string derived2TemplatePreprocessing = t4.PreprocessTemplate(filePath, File.ReadAllText(filePath), cb, "DerivedTemplate2", "AbstractTemplating.Templates2", out reference);
File.WriteAllText(Path.Combine("..\\..\\Templates2", "AbstractTemplate.cs"), abstractTemplatePreprocessing, cb.outputEncoding);
File.WriteAllText(Path.Combine("..\\..\\Templates2", "DerivedTemplate2.cs"), derived2TemplatePreprocessing, cb.outputEncoding);
string result = t4.ProcessTemplate("..\\..\\Templates2\\AbstractTemplate.cs", derived2TemplatePreprocessing, cb);
string resultFileName = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)) + "_gen" + cb.fileExtension;
// Write the processed output to file:
File.WriteAllText(resultFileName, result, cb.outputEncoding);
// Append any error messages:
if (cb.errorMessages.Count > 0)
{
File.AppendAllLines(resultFileName, cb.errorMessages);
}
}
但是在这种情况下,是DerivedTemplate2:AbstractTemplate的结果C#代码,类似于模板作为解决方案的一部分并构建解决方案的情况。
所以最后我的问题是可以用这种方式调用抽象和派生模板吗?如果是,请举例说明如何实现这一目标。谢谢
答案 0 :(得分:0)
这只是一种意见,而是关于您所描述的主题:
1)不会向用户隐藏模板(将模板与生成的代码一起提交到解决方案中)-VS MVC-Entity-Extension做到这一点的方法是相反的-但在这种情况下MS是错误的(并且普及率较低) MS世界中的代码生成就是对此的证明)。如果必须生成100个文件,则还要生成100个模板。但是更好的模板是在一个文件中生成一百个类。
2)不要将代码生成和实现继承混合在一起-它们是相互正交的。首先是用于以用户可以更改“所有内容”的形式向用户发布“所有内容”,其次是隐藏详细信息(如果要为用户提供“更改所有内容”功能,为什么要隐藏详细信息)?