Visual Studio 2015高级编程(第6版)
上QQ阅读APP看书,第一时间看更新

14.2 T4构建基块

每个T4模板都由许多影响所生成文件的块组成。第一个例子中的Hello World代码行就是一个Text块。Text块会从模板文件完整地复制到生成的文件中。它们可以包含任意文本,也可以包含其他块。

除了Text块之外,还有3种类型的块:Expression块、Statement块和Class Feature块。这些块都放在特定类型的标记中,以标识它们。Text块是唯一没有特定标记的块。

14.2.1 Expression块

Expression块用于把一些计算出来的值传递到生成的文件中。Expression块一般显示在Text块内部,用<#=和#>标记来表示。下面的模板示例输出了生成文件的日期和时间:

C#

      <#@ template debug="false" hostspecific="false" language="C#" #>
      <#@ output extension=".txt" #>
      This file was generated: <#=System.DateTime.Now #>

VB

      <#@ template debug="false" hostspecific="false" language="VB" #>
      <#@ output extension=".txt" #>
      This file was generated: <#=System.DateTime.Now #>

块中的表达式可以是用template指令指定的模板语言编写的任意有效表达式。每次运行时,模板都会计算该表达式,再对结果调用ToString()。之后把这个值插入到生成的文件中。

14.2.2 Statement块

Statement块用于在运行模板时执行任意语句。Statement块中的代码可以记录模板的执行、创建临时变量,或者从计算机中删除文件,所以需要特别小心。实际上,Statement块中的代码可以包含用模板语言编写的任意有效语句。Statement块一般用于实现模板内部的流控制、管理临时变量,以及与其他系统交互操作。Statement块用<#和#>标记表示,这些标记类似于Expression块的分隔符,但没有等号。下面的例子生成的文件包含一首流行祝酒歌中的全部99行诗句。

C#

      <#@ template debug="false" hostspecific="false" language="C#" #>
      <#@ output extension=".txt" #>
      <# for( int i = 99; i > = 1; )
         { #>
      <#=i #> Bottles of Non-alcoholic Carbonated Beverage on the wall
      <#=i #> Bottles of Non-alcoholic Carbonated Beverage
      Take one down
      And pass it around
      <# if( i-1 == 0 ) { #>
      There's no Bottles of Non-alcoholic Carbonated Beverage on the wall
      <# } else { #>
      There's <#=i-1 #> Bottles of Non-alcoholic Carbonated Beverage on the wall
      <# } #>
        <# } #>

VB

      <#@ template debug="false" hostspecific="false" language="VB" #>
      <#@ output extension=".txt" #>
      <# For i As Integer = 99 To 1 Step -1 #>
        <#= i #> Bottles of Non-alcoholic Carbonated Beverage on the wall
        <#= i #> Bottles of Non-alcoholic Carbonated Beverage
        Take one down
        And pass it around
      <# If i - 1 = 0 Then #>
        There's no Bottles of Non-Alcoholic Carbonated Beverage on the wall.
      <# Else #>
        There's <#= i-1 #> Bottles of Non-alcoholic Carbonated Beverage on the wall.
      <# End If #>
      <# Next #>

在上面的例子中,Statement块包含了一个Text块,该Text块又包含许多Expression块。使用这3个块类型可以创建出非常强大的模板。

虽然例子中的Statement块包含其他块,但这并不是必需的。在Statement块中,可以使用Write()和WriteLine()方法直接写入生成的文件。下面是使用这个方法的例子。

C#

      <#@ template debug="false" hostspecific="false" language="C#" #>
      <#@ output extension=".txt" #>
      <#
      for( int i = 99; i > 1; i-- )
      {
        WriteLine( "{0} Bottles of Non-alcoholic Carbonated Beverage on the wall", i);
        WriteLine( "{0} Bottles of Non-alcoholic Carbonated Beverage", i );
        WriteLine ( "Take one down" );
        WriteLine( "And pass it around" );
        if( i - 1 == 0 ) {
          WriteLine(
            "There's no Bottles of Non-alcoholic Carbonated Beverage on the wall." );
        } else {
          WriteLine(
            "There's {0} Bottles of Non-alcoholic Carbonated Beverage on the wall.",i-1);
        }
        WriteLine( "" );
      } #>

VB

      <#@ template debug="false" hostspecific="false" language="VB" #>
      <#@ output extension=".txt" #>
      <# For i As Integer = 99 To 1 Step -1
        Me.WriteLine("{0} Bottles of Non-alcoholic Carbonated Beverage on the wall", i)
        Me.WriteLine("{0} Bottles of Non-alcoholic Carbonated Beverage", i)
        Me.WriteLine("Take one down")
        Me.WriteLine("And pass it around")
        If i - 1 = 0 Then
          WriteLine("There's no Bottles of Non-Alcoholic Carbonated Beverage on the" & _
           " wall.")
        Else
          WriteLine("There's {0} Bottles of Non-alcoholic Carbonated Beverage on the" & _
           " wall.",i-1)
        End If
        Me.WriteLine( "" )
        Next #>

这两个模板生成的最终结果相同。根据模板,可能会发现某种方法比另一种方法更容易理解。建议在每个模板中仅使用一种方法,以避免混乱。

14.2.3 Class Feature块

T4块的最后一种类型是Class Feature块。该块包含可以在Statement块和Expression块中调用的任意代码,以帮助生成需要的文件。它常常包含定制的格式化代码或重复的任务。Class Feature块使用<#+和#>标记表示,这些标记类似于表示Expression块的标记,但开始标记中的等号变成了加号。下面的模板使用一种典型的财务格式写入−5~5的数字,每个数字都有两位小数,前面还有一个美元符号,负数写成正数,但加上括号。

C#

      <#@ template debug="false" hostspecific="false" language="C#" #>
      <#@ output extension=".txt" #>
      Financial Sample Data
      <# for( int i = -5; i <= 5; i++ )
         {
           WriteFinancialNumber(i);
               WriteLine( "" );
         } #>
      End of Sample Data
       <#+
         void WriteFinancialNumber(decimal amount)
         {
           if( amount < 0 )
             Write("(${0:#0.00})", System.Math.Abs(amount) );
           else
              Write("${0:#0.00}", amount);
         }
         #>

VB

      <#@ template debug="true" hostspecific="false" language="VB" #>
      <#@ output extension=".txt" #>
      Financial Sample Data
      <# For i as Integer = -5 To 5
         WriteFinancialNumber(i)
         WriteLine( "" )
       Next  #>
      End of Sample Data
      <#+
      Sub WriteFinancialNumber(amount as Decimal)
        If amount < 0 Then
          Write("(${0:#0.00})", System.Math.Abs(amount) )
        Else
          Write("${0:#0.00}", amount)
        End If
      End Sub
      #>

Class Feature块可以包含Text块和Expression块,但不能包含Statement块。此外,一旦遇到Class Feature块,就不允许出现Statement块。

了解到可以出现在模板文件中的不同类型的T4块后,下面看看Visual Studio 2015如何使用它们生成输出文件。