饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 43 页

作者:Nick Randolph/等 当前章节:15393 字 更新时间:2026-6-18 14:51

relevant area of the template.

One interesting exception to the way that Visual Studio handles invalid

directives is the extension attribute of the output directive. If the value supplied

is invalid in any way, a warning is raised but the generated fi le is not produced

at all. If you have other code that depends on the contents of the generated fi le,

the background compilation process will quickly fi nd a cascade of errors, which

can be overwhelming. Check to see if the fi le is being generated at all before

attempting to fi x the template by temporarily removing all the contents of the

template fi le except for the template and output directives.

One of the other fi les generated by turning debugging on is a .cmdline fi le,

which contains arguments that are passed to csc.exe or vbc.exe when

T4 compiles the template. You can use this fi le to re - create the compilation

process. There is also a fi le with the .out extension, which contains the

command line call to the compiler and its results.

executing transformation errors

The fi nal step in the T4 pipeline that might generate errors is when the code generator is actually

instantiated and executed to produce the contents of the generated fi le. This stage is essentially

running arbitrary .NET code and is the most likely to encounter trouble with environmental

conditions or faulty logic. Like Compiling Transformation errors, errors found during this stage

have a prefi x of Executing Transformation, which makes them easy to spot.

The best way of handling Executing Transformation errors is to code defensively. From within the

T4 template, if you can detect an error condition such as a fi le missing or being unable to connect

to a database, you can use the Error() method to notify the engine of the specifi c problem. These

Troubleshooting . 279

280 .

chaPter 14 code generATion WiTh T4

errors will appear as Executing Transformation errors just like all of the others, only they’ll have a

more contextual, and hence, more useful message associated with them:

if( !File.Exists(fileName) ) {

this.Error("Cannot find file");

}

In addition to Error() there is an equivalent Warning() method to raise warnings.

If the T4 template encounters an error that is catastrophic, such as not being able to connect to the

database that it gets its data from, it is able to throw an exception to halt the execution process. The

details about the exception are gathered and included in the Error List tool window.

Generated code errors

Although not technically a part of the T4 process, the generated file can just as easily contain

compile-time or run time errors. In the case of compile-time errors, Visual Studio is simply able

to detect these as normal. For run time errors it is probably a good idea to unit test complex types

anyway, even those that have been generated.

Now that you know what to do when things go wrong, it is time to look at a larger example.

GeneratinG code assets

When you develop enterprise applications, you will frequently come across reference data that

rarely changes and is represented in code as an enumeration type. The task of keeping the data

in the database and the values of the enumerated type in sync is time-consuming and repetitive,

which makes it a perfect candidate to automate with a T4 template. The template presented in this

section connects to the AdventureWorks example database and creates an enumeration based on the

contents of the Sales.ContactType table.

c#

<<#@ template debug=”false” hostspecific=”false” language=”C#” #>

<#@ output extension=”.generated.cs” #>

<#@ assembly name=”System.Data” #>

<#@ import namespace=”System.Data.SqlClient” #>

<#@ import namespace=”System.Text.RegularExpressions” #>

<#

var connectionString = “Data Source=.\\SQLEXPRESS; Initial Catalog=AdventureWorks;”

+ “Integrated Security=true;”;

var sqlString = “SELECT ContactTypeID, [Name] FROM [Person].[ContactType]”;

#>

// This code is generated. Please do not edit it directly

// If you need to make changes please edit ContactType.tt instead

namespace AdventureWorks {

Generating Code assets .

281

public enum ContactType {

<#

using(var conn = new SqlConnection(connectionString))

using(var cmd = new SqlCommand(sqlString, conn))

{

conn.Open();

var contactTypes = cmd.ExecuteReader();

while( contactTypes.Read() )

{

#>

<#= ValidIdentifier( contactTypes[1].ToString() ) #> = <#=contactTypes[0]#>,

<#}

conn.Close();

}

#>

}

}

<#+

public string ValidIdentifier(string input)

{

return Regex.Replace(input, @”[^a-zA-Z0-9]”, String.Empty );

}

#>

Code snippet ContactTypes.tt

Vb

<#@ template debug=”false” hostspecific=”false” language=”VB” #>

<#@ output extension=”.generated.vb” #>

<#@ assembly name=”System.Data” #>

<#@ import namespace=”System.Data.SqlClient” #>

<#@ import namespace=”System.Text.RegularExpressions” #>

<#

Dim ConnectionString as String = “Data Source=.\SQLEXPRESS; “ _

& “Initial Catalog=AdventureWorks; Integrated Security=true;”

Dim SqlString as String = “SELECT ContactTypeID,[Name] FROM [Person].[ContactType]”

#>

‘ This code is generated. Please do not edit it directly

‘ If you need to make changes please edit ContactType.tt instead

Namespace AdventureWorks

Enum ContactType

<#

Using Conn As New SqlConnection(ConnectionString), _

continues

282 .

chaPter 14 code generATion WiTh T4

(continued)

Cmd As New SqlCommand(SqlString, Conn)

Conn.Open()

Dim ContactTypes As SqlDataReader = Cmd.ExecuteReader()

While ContactTypes.Read()

#>

<#= ValidIdentifier( contactTypes(1).ToString() ) #> = <#=contactTypes(0)#>

<#

End While

Conn.Close()

End Using

#>

End Enum

End Namespace

<#+

Public Function ValidIdentifier(Input as String) As String

Return Regex.Replace(Input, “[^a-zA-Z0-9]”, String.Empty )

End Function

#>

Code snippet ContactTypes.tt

The first section is made up of T4 directives. The first two specify the language for the template and

the extension of the output file. The third attaches an assembly to the generator (to provide access

to the System.Data.SqlClient namespace), and the final two import namespaces into the template

that the template code requires.

The next section is a T4 Statement block. It contains some variables that the template will be using.

Putting them at the top of the template file makes them easier to find later on in case they need to change.

After the variable declarations there is a T4 Text block containing some explanatory comments

along with a namespace and an enumeration declaration. These are copied verbatim into the

generated output file. It’s usually a good idea to provide a comment inside the generated file

explaining where they come from and how to edit them. This prevents nasty accidents when changes

are erased after a file is regenerated.

The bulk of the rest of the template is taken up by a Statement block. This block creates and opens a

connection to the AdventureWorks database using the variables defined in the first Statement block.

It then queries the database to retrieve the desired data with a data reader.

For each record retrieved from the database a Text block is produced. This Text block consists

of two Expression blocks separated by an equals sign. The second expression merely adds the

ID of the Contact Type to the generated output file. The first one calls a helper method called

ValidIdentifier, which is defined in a Class Feature block that creates a valid identifier for each

contact type by removing all invalid characters from the Contact Type Name.

The generated output file is shown in the following listing. The end result looks fairly simple in

comparison to the script that is used to generate it, but this is a little deceiving. The T4 template can

remain the same as rows of data are added to and removed from the ContactType table. In fact, the

Generating Code assets .

283

items in the database can be completely re-ordered and your code will still compile. With a little

modification this script can even be used to generate enumerated types from a number of different

tables at once.

c#

// This code is generated. Please do not edit it directly

// If you need to make changes please edit ContactType.tt instead

namespace AdventureWorks {

public enum ContactType {

AccountingManager = 1,

AssistantSalesAgent = 2,

AssistantSalesRepresentative = 3,

CoordinatorForeignMarkets = 4,

ExportAdministrator = 5,

InternationalMarketingManager = 6,

MarketingAssistant = 7,

MarketingManager = 8,

MarketingRepresentative = 9,

OrderAdministrator = 10,

Owner = 11,

OwnerMarketingAssistant = 12,

ProductManager = 13,

PurchasingAgent = 14,

PurchasingManager = 15,

RegionalAccountRepresentative = 16,

SalesAgent = 17,

SalesAssociate = 18,

SalesManager = 19,

SalesRepresentative = 20,

}

}

Code snippet ContactTypes.generated.cs

Vb

' This code is generated. Please do not edit it directly

' If you need to make changes please edit ContactType.tt instead

Namespace AdventureWorks

Enum ContactType

AccountingManager = 1

AssistantSalesAgent = 2

AssistantSalesRepresentative = 3

CoordinatorForeignMarkets = 4

ExportAdministrator = 5

InternationalMarketingManager = 6

MarketingAssistant = 7

MarketingManager = 8

MarketingRepresentative = 9

OrderAdministrator = 10

Owner = 11

OwnerMarketingAssistant = 12

continues

284 .

chaPter 14 code generATion WiTh T4

(continued)

ProductManager = 13

PurchasingAgent = 14

PurchasingManager = 15

RegionalAccountRepresentative = 16

SalesAgent = 17

SalesAssociate = 18

SalesManager = 19

SalesRepresentative = 20

End Enum

End Namespace

Code snippet ContactTypes.generated.vb

PreProcessed text teMPlates

Text Template Transformation is a powerful technique and it shouldn’t be restricted to a design-time

activity. Visual Studio 2010 makes it easy to take advantage of the T4 engine to create your own

text template generators to use in your own projects. These generators are called Preprocessed Text

Templates.

To create a new Preprocessed Text Template, open the Add New Item dialog, select the General

page, and select Preprocessed Text Template from the list of items. The newly created file has the

same .tt extension as normal T4 template files and contains a single T4 directive:

c#

<#@ template language="C#" #>

Vb

<#@ template language="VB" #>

Note that there is no output directive. The generated file will have the same filename as the

template file but the .tt will be replaced with .vb or .cs depending on your project language.

When this file is saved, it generates an output file like the following.

c#

// ---------------------------------------------------------------------------//

<auto-generated>

// This code was generated by a tool.

// Runtime Version: 10.0.0.0

//

// Changes to this file may cause incorrect behavior and will be lost if

// the code is regenerated.

// </auto-generated>

// ---------------------------------------------------------------------------namespace

Chapter_14

{

Preprocessed Text Templates .

285

using System;

public partial class NewTemplate

{

// region Fields

// region Properties

// region Transform-time helpers

public virtual string TransformText()

{

return this.GenerationEnvironment.ToString();

}

}

}

Code snippet NewTemplate.cs

Vb

Imports System

'-----------------------------------------------------------------------------'

< auto-generated >

' This code was generated by a tool.

' Runtime Version: 10.0.0.0

'

' Changes to this file may cause incorrect behavior and will be lost if

' the code is regenerated.

' < /auto-generated >

'------------------------------------------------------------------------------

Namespace My.Templates

Partial Public Class NewTemplate

' Region "Fields"

' Region "Properties"

' Region "Transform-time helpers"

Public Overridable Function TransformText() As String

Return Me.GenerationEnvironment.ToString

End Function

End Class

End Namespace

Code snippet NewTemplate.vb

This is very much like the interim code file that is produced by T4 for a normal template. This

generated class is now just a class inside the project, which means you can instantiate it, fill in its

properties, and call TransformText() on it.

Just as with a normal Text Template, Visual Studio uses a Custom Tool to

generate the output file of a Preprocessed Text Template. Instead of using the

TextTemplatingFileGenerator custom tool, Preprocessed Text Templates are

transformed using the TextTemplatingFilePreprocessor custom tool, which

adds the code generator class to your project instead of the results of executing

the code generator.

286 .

chaPter 14 code generATion WiTh T4

using Preprocessed text templates

To demonstrate how to use a Preprocessed Text Template within your own code, this section

presents a simple scenario. The project needs to be able to send a standard welcome letter to new

club members when they join the AdventureWorks Cycle club. The following Preprocessed Text

Template contains the basic letter that is to be produced.

c#

<#@ template language="C#" #>

Dear <#=Member.Salutation#> <#=Member.Surname#>,

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页