在 Visual Studio 扩展中调用文本转换

如果要编写 Visual Studio 扩展(如菜单命令或 特定于域的语言),则可以使用文本模板化服务转换文本模板。 获取STextTemplating服务并将其转换为ITextTemplating

获取文本模板化服务

using Microsoft.VisualStudio.TextTemplating;
using Microsoft.VisualStudio.TextTemplating.VSHost;
...
// Get a service provider - how you do this depends on the context:
IServiceProvider serviceProvider = ...; // An instance of EnvDTE, for example

// Get the text template service:
ITextTemplating t4 = serviceProvider.GetService(typeof(STextTemplating)) as ITextTemplating;

// Process a text template:
string result = t4.ProcessTemplate(filePath, System.IO.File.ReadAllText(filePath));

将参数传递给模板

可以将参数传递到模板中。 在模板中,可以使用该指令获取参数值 <#@parameter#>

对于参数类型,必须使用可序列化的或可封送的类型。 也就是说,必须用SerializableAttribute声明该类型,或者必须从MarshalByRefObject派生该类型。 此限制是必需的,因为文本模板是在单独的 AppDomain 中执行的。 所有内置类型(如 System.StringSystem.Int32 )都是可序列化的。

若要传递参数值,调用代码可以将值放置在 Session 字典中,或放置在 CallContext

以下示例使用这两种方法转换短测试模板:

using Microsoft.VisualStudio.TextTemplating;
using Microsoft.VisualStudio.TextTemplating.VSHost;
...
// Get a service provider - how you do this depends on the context:
IServiceProvider serviceProvider = dte;

// Get the text template service:
ITextTemplating t4 = serviceProvider.GetService(typeof(STextTemplating)) as ITextTemplating;
ITextTemplatingSessionHost sessionHost = t4 as ITextTemplatingSessionHost;

// Create a Session in which to pass parameters:
sessionHost.Session = sessionHost.CreateSession();
sessionHost.Session["parameter1"] = "Hello";
sessionHost.Session["parameter2"] = DateTime.Now;

// Pass another value in CallContext:
System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("parameter3", 42);

// Process a text template:
string result = t4.ProcessTemplate("",
   // This is the test template:
   "<#@parameter type=\"System.String\" name=\"parameter1\"#>"
 + "<#@parameter type=\"System.DateTime\" name=\"parameter2\"#>"
 + "<#@parameter type=\"System.Int32\" name=\"parameter3\"#>"
 + "Test: <#=parameter1#>    <#=parameter2#>    <#=parameter3#>");

// This test code yields a result similar to the following line:
//     Test: Hello    07/06/2010 12:37:45    42

错误报告和输出指令

在处理过程中出现的任何错误都将显示在 Visual Studio 错误窗口中。 此外,还可以通过指定实现 ITextTemplatingCallback 的回调来通知错误。

如果要将结果字符串写入文件,可能需要知道在模板中的指令中 <#@output#> 指定了哪些文件扩展名和编码。 此信息也将传递给回调。 有关详细信息,请参阅 T4 输出指令

void ProcessMyTemplate(string MyTemplateFile)
{
  string templateContent = File.ReadAllText(MyTemplateFile);
  T4Callback cb = new T4Callback();
  // Process a text template:
  string result = t4.ProcessTemplate(MyTemplateFile, templateContent, cb);
  // If there was an output directive in the MyTemplateFile,
  // then cb.SetFileExtension() will have been called.
  // Determine the output file name:
  string resultFileName =
    Path.Combine(Path.GetDirectoryName(MyTemplateFile),
        Path.GetFileNameWithoutExtension(MyTemplateFile))
      + 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);
  }
}

class T4Callback : ITextTemplatingCallback
{
  public List<string> errorMessages = new List<string>();
  public string fileExtension = ".txt";
  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; }
}

可以使用如下所示的模板文件测试代码:

<#@output extension=".htm" encoding="ASCII"#>
<# int unused;  // Compiler warning "unused variable"
#>
Sample text.

编译器警告将显示在 Visual Studio 错误窗口中,并生成对 ErrorCallback 的调用。

引用参数

可以使用派生自 MarshalByRefObject的参数类将值传出文本模板。

若要从预处理的文本模板生成文本:调用 TransformText() 生成的类的方法。 有关详细信息,请参阅 使用 T4 文本模板进行运行时文本生成

若要在 Visual Studio 扩展外部生成文本:定义自定义主机。 有关详细信息,请参阅 使用自定义主机处理文本模板

若要生成稍后可以编译和执行的源代码:调用 ITextTemplatingPreprocessTemplate 方法。