Share via


T4 텍스트 템플릿을 사용하여 런타임 텍스트 생성

Visual Studio 런타임 텍스트 템플릿을 사용하여 런타임에 애플리케이션에서 텍스트 문자열을 생성할 수 있습니다. 애플리케이션이 실행되는 컴퓨터에는 Visual Studio가 필요가 없습니다. 런타임 템플릿은 컴파일 시간에 런타임에서 실행되는 코드를 생성하기 때문에 "전처리된 텍스트 템플릿"이라고도 합니다.

각 템플릿은 생성된 문자열과 프로그램 코드 조각에 표시되는 텍스트의 혼합입니다. 프로그램 조각은 문자열의 변수 부분에 대한 값을 제공하고 조건부 및 반복되는 부분도 제어합니다.

예를 들어 HTML 보고서를 만드는 애플리케이션에서 다음 템플릿을 사용할 수 있습니다.

<#@ template language="C#" #>
<html><body>
<h1>Sales for Previous Month</h2>
<table>
    <# for (int i = 1; i <= 10; i++)
       { #>
         <tr><td>Test name <#= i #> </td>
             <td>Test value <#= i * i #> </td> </tr>
    <# } #>
 </table>
This report is Company Confidential.
</body></html>

템플릿은 변수 부분이 프로그램 코드로 대체된 HTML 페이지입니다. HTML 페이지의 정적 프로토타입을 작성하여 이러한 페이지의 디자인을 시작할 수 있습니다. 그런 다음 테이블 및 기타 변수 부분을 경우마다 다른 콘텐츠를 생성하는 프로그램 코드로 바꿀 수 있습니다.

애플리케이션에서 템플릿을 사용하면 출력의 최종 형식을 보다 쉽게 확인할 수 있습니다(예: 긴 일련의 쓰기 문). 출력 형식을 변경하는 것이 더 쉽고 안정적입니다.

애플리케이션에서 런타임 텍스트 템플릿 만들기

런타임 텍스트 템플릿을 만들려면

  1. 솔루션 탐색기의 프로젝트에 대한 바로 가기 메뉴에서 추가>새 항목을 선택합니다.

  2. 새 항목 추가 대화 상자에서 런타임 텍스트 템플릿을 선택합니다. (Visual Basic에서 일반 항목>일반 아래를 살펴봅니다.)

  3. 템플릿 파일의 이름을 입력합니다.

    참고 항목

    템플릿 파일 이름은 생성된 코드에서 클래스 이름으로 사용됩니다. 따라서 공백이나 문장 부호가 없어야 합니다.

  4. 추가를 선택합니다.

    확장명 .tt가 포함된 새 파일이 만들어집니다. 사용자 지정 도구 속성은 TextTemplatingFilePreprocessor로 설정됩니다. 여기에는 다음 줄이 포함되어 있습니다.

    <#@ template language="C#" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Collections.Generic" #>
    
  5. NuGet 패키지 System.CodeDom에 대한 참조를 추가합니다.

기존 파일을 런타임 템플릿으로 변환

템플릿을 만드는 좋은 방법은 출력의 기존 예제를 변환하는 것입니다. 예를 들어 애플리케이션에서 HTML 파일을 생성하는 경우 일반 HTML 파일을 만들어 시작할 수 있습니다. 제대로 작동하고 형태가 올바른지 확인합니다. 그런 다음, Visual Studio 프로젝트에 포함하고 템플릿으로 변환합니다.

기존 텍스트 파일을 런타임 템플릿으로 변환

  1. Visual Studio 프로젝트에 파일을 포함합니다. 솔루션 탐색기의 프로젝트 바로 가기 메뉴에서 추가>기존 항목을 선택합니다.

  2. 파일의 사용자 지정 도구 속성을 TextTemplatingFilePreprocessor로 설정합니다. 솔루션 탐색기의 파일 바로 가기 메뉴에서 속성을 선택합니다.

    참고 항목

    속성이 이미 선택된 경우 TextTemplatingFileGenerator가 아닌 TextTemplatingFilePreprocessor인지 확인합니다. 이 문제는 확장명 .tt가 이미 있는 파일을 포함하는 경우에 발생할 수 있습니다.

  3. 파일 확장명을 .tt로 변경합니다. 이 단계는 선택 사항이지만 잘못된 편집기에서 파일을 열지 않는 데 도움이 됩니다.

  4. 파일 이름의 주 부분에서 공백 또는 문장 부호를 제거합니다. 예를 들어 "My Web Page.tt"는 올바르지 않지만 "MyWebPage.tt"는 괜찮습니다. 파일 이름은 생성된 코드에서 클래스 이름으로 사용됩니다.

  5. 파일의 시작 부분에 다음 줄을 삽입합니다. Visual Basic 프로젝트에서 작업하는 경우 "C#"을 "VB"로 대체합니다.

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

  6. NuGet 패키지 System.CodeDom에 대한 참조를 추가합니다.

런타임 템플릿의 콘텐츠

템플릿 지시문

파일을 만들 때와 마찬가지로 템플릿의 첫 번째 줄을 유지합니다.

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

언어 매개 변수는 프로젝트의 언어에 따라 달라집니다.

일반 콘텐츠

애플리케이션에서 생성할 텍스트를 포함하도록 .tt 파일을 편집합니다. 예시:

<html><body>
<h1>Sales for January</h2>
<!-- table to be inserted here -->
This report is Company Confidential.
</body></html>

포함된 프로그램 코드

<##> 사이에 프로그램 코드를 삽입할 수 있습니다. 예시:

<table>
    <# for (int i = 1; i <= 10; i++)
       { #>
         <tr><td>Test name <#= i #> </td>
             <td>Test value <#= i * i #> </td> </tr>
    <# } #>
 </table>

문은 <# ... #> 사이에 삽입되고 식은 <#= ... #> 사이에 삽입됩니다. 자세한 내용은 T4 텍스트 템플릿 작성을 참조하세요.

템플릿 사용

템플릿에서 빌드된 코드

.tt 파일을 저장하면 보조 .cs 또는 .vb 파일이 생성됩니다. 솔루션 탐색기에서 이 파일을 보려면 .tt 파일 노드를 확장합니다. Visual Basic 프로젝트에서 먼저 솔루션 탐색기 도구 모음의 모든 파일 표시를 선택합니다.

보조 파일에는 TransformText()라는 메서드가 포함된 partial 클래스가 있습니다. 애플리케이션에서 이 메서드를 호출할 수 있습니다.

런타임에서 텍스트 생성

애플리케이션 코드에서 다음과 같은 호출을 사용하여 템플릿의 콘텐츠를 생성할 수 있습니다.

MyWebPage page = new MyWebPage();
String pageContent = page.TransformText();
System.IO.File.WriteAllText("outputPage.html", pageContent);

생성된 클래스를 특정 네임스페이스에 배치하려면 텍스트 템플릿 파일에서 사용자 지정 도구 네임스페이스 속성을 설정합니다.

런타임 텍스트 템플릿 디버깅

일반 코드와 동일한 방식으로 런타임 텍스트 템플릿을 디버그하고 테스트합니다.

텍스트 템플릿에서 중단점을 설정할 수 있습니다. Visual Studio의 디버깅 모드에서 애플리케이션을 시작하는 경우 코드를 단계별로 진행하여 일반적인 방식으로 watch 식을 평가할 수 있습니다.

생성자에 매개 변수 전달

보통 템플릿은 애플리케이션의 다른 부분에서 일부 데이터를 가져와야 합니다. 이 작업을 쉽게 하기 위해 템플릿에서 빌드한 코드가 부분적 클래스입니다. 프로젝트의 다른 파일에서 동일한 클래스의 다른 부분을 만들 수 있습니다. 해당 파일에는 템플릿에 포함된 코드와 애플리케이션의 나머지 부분 모두에서 액세스할 수 있는 매개 변수, 속성 및 함수와 생성자가 포함될 수 있습니다.

예를 들어 별도의 파일인 MyWebPageCode.cs를 만들 수 있습니다.

partial class MyWebPage
{
    private MyData m_data;
    public MyWebPage(MyData data) { this.m_data = data; }}

템플릿 파일 MyWebPage.tt에서 다음을 작성할 수 있습니다.

<h2>Sales figures</h2>
<table>
<# foreach (MyDataItem item in m_data.Items)
   // m_data is declared in MyWebPageCode.cs
   { #>
      <tr><td> <#= item.Name #> </td>
          <td> <#= item.Value #> </td></tr>
<# } // end of foreach
#>
</table>

애플리케이션에서 이 템플릿을 사용하려면 다음을 수행합니다.

MyData data = ...;
MyWebPage page = new MyWebPage(data);
String pageContent = page.TransformText();
System.IO.File.WriteAllText("outputPage.html", pageContent);

Visual Basic의 생성자 매개 변수

Visual Basic에서 별도의 파일 MyWebPageCode.vb에는 다음이 포함됩니다.

Namespace My.Templates
  Partial Public Class MyWebPage
    Private m_data As MyData
    Public Sub New(ByVal data As MyData)
      m_data = data
    End Sub
  End Class
End Namespace

템플릿 파일에는 다음이 포함될 수 있습니다.

<#@ template language="VB" #>
<html><body>
<h1>Sales for January</h2>
<table>
<#
    For Each item In m_data.Items
#>
    <tr><td>Test name <#= item.Name #> </td>
      <td>Test value <#= item.Value #> </td></tr>
<#
    Next
#>
</table>
This report is Company Confidential.
</body></html>

생성자에서 매개 변수를 전달하여 템플릿을 호출할 수 있습니다.

Dim data = New My.Templates.MyData
    ' Add data values here ....
Dim page = New My.Templates.MyWebPage(data)
Dim pageContent = page.TransformText()
System.IO.File.WriteAllText("outputPage.html", pageContent)

템플릿 속성에 데이터 전달

데이터를 템플릿에 전달하는 또 다른 방법은 partial 클래스 정의에서 템플릿 클래스에 공용 속성을 추가하는 것입니다. 애플리케이션은 TransformText()를 호출하기 전에 속성을 설정할 수 있습니다.

부분적 정의에서 템플릿 클래스에 필드를 추가할 수도 있습니다. 이렇게 하면 템플릿의 연속 실행 간에 데이터를 전달할 수 있습니다.

코드에 partial 클래스 사용

많은 개발자는 템플릿에서 가급적 큰 코드 본문을 작성하지 않는 편을 선호합니다. 대신 템플릿 파일과 이름이 같은 partial 클래스에서 메서드를 정의할 수 있습니다. 템플릿에서 해당 메서드를 호출합니다. 이러한 방식으로 템플릿은 대상 출력 문자열의 형태를 보다 명확하게 표시합니다. 결과의 형태에 대한 논의는 표시되는 데이터를 만드는 논리와 구분할 수 있습니다.

어셈블리 및 참조

템플릿 코드가 .NET 또는 System.Xml.dll같은 다른 어셈블리를 참조하도록 하려면 일반적인 방식으로 프로젝트의 참조에 추가합니다.

using 문과 동일한 방식으로 네임스페이스를 가져오려면 import 지시문을 사용하여 이 작업을 수행하면 됩니다.

<#@ import namespace="System.Xml" #>

이러한 지시문은 <#@template 지시문 바로 뒤의 파일 시작 부분에 배치해야 합니다.

공유 콘텐츠

여러 템플릿 간에 공유되는 텍스트가 있는 경우 별도의 파일에 배치한 다음 표시되어야 하는 각 파일에 포함하면 됩니다.

<#@include file="CommonHeader.txt" #>

포함된 콘텐츠는 프로그램 코드와 일반 텍스트를 혼합하여 포함할 수 있으며 다른 include 지시문 및 기타 지시문을 포함할 수 있습니다.

Include 지시문은 템플릿 파일이나 포함된 파일의 텍스트 내 모든 위치에서 사용할 수 있습니다.

런타임 텍스트 템플릿 간 상속

추상일 수 있는 기본 클래스 템플릿을 작성하여 런타임 템플릿 간에 콘텐츠를 공유할 수 있습니다. <@#template#> 지시문의 inherits 매개 변수를 사용하여 다른 런타임 템플릿 클래스를 참조합니다.

상속 패턴: 기본 메서드의 조각

뒤에 나오는 예제에서 사용된 패턴에서 다음 사항을 확인합니다.

  • 기본 클래스 SharedFragments는 클래스 기능 블록 <#+ ... #> 내에서 메서드를 정의합니다.

  • 기본 클래스에는 자유 텍스트가 포함되어 있지 않습니다. 대신 모든 텍스트 블록이 클래스 기능 메서드 내에서 발생합니다.

  • 파생 클래스는 SharedFragments에 정의된 메서드를 호출합니다.

  • 애플리케이션은 파생 클래스의 TextTransform() 메서드를 호출하지만 기본 클래스 SharedFragments를 변환하지는 않습니다.

  • 기본 클래스와 파생 클래스 모두 런타임 텍스트 템플릿입니다. 즉, 사용자 지정 도구 속성이 TextTemplatingFilePreprocessor로 설정됩니다.

SharedFragments.tt:

<#@ template language="C#" #>
<#+
protected void SharedText(int n)
{
#>
   Shared Text <#= n #>
<#+
}
// Insert more methods here if required.
#>

MyTextTemplate1.tt:

<#@ template language="C#" inherits="SharedFragments" #>
begin 1
   <# SharedText(2); #>
end 1

MyProgram.cs:

...
MyTextTemplate1 t1  = new MyTextTemplate1();
string result = t1.TransformText();
Console.WriteLine(result);

결과 출력:

begin 1
    Shared Text 2
end 1

상속 패턴: 기본 본문의 텍스트

템플릿 상속 사용에 대한 이 대체 방식의 경우 텍스트의 대부분이 기본 템플릿에서 정의됩니다. 파생된 템플릿은 기본 콘텐츠에 맞는 데이터 및 텍스트 조각을 제공합니다.

AbstractBaseTemplate1.tt:

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

Here is the description for this derived template:
  <#= this.Description #>

Here is the fragment specific to this derived template:
<#
  this.PushIndent("  ");
  SpecificFragment(42);
  this.PopIndent();
#>
End of common template.
<#+
  // State set by derived class before calling TextTransform:
  protected string Description = "";
  // 'abstract' method to be defined in derived classes:
  protected virtual void SpecificFragment(int n) { }
#>

DerivedTemplate1.tt:

<#@ template language="C#" inherits="AbstractBaseTemplate1" #>
<#
  // Set the base template properties:
  base.Description = "Description for this derived class";

  // Run the base template:
  base.TransformText();

#>
End material for DerivedTemplate1.

<#+
// Provide a fragment specific to this derived template:

protected override void SpecificFragment(int n)
{
#>
   Specific to DerivedTemplate1 : <#= n #>
<#+
}
#>

애플리케이션 코드:

...
DerivedTemplate1 t1 = new DerivedTemplate1();
string result = t1.TransformText();
Console.WriteLine(result);

결과 출력:

Here is the description for this derived template:
  Description for this derived class

Here is the fragment specific to this derived template:
     Specific to DerivedTemplate1 : 42
End of common template.
End material for DerivedTemplate1.

디자인 타임 템플릿: 템플릿을 사용하여 애플리케이션의 일부가 되는 코드를 생성하려면 T4 텍스트 템플릿을 사용하여 디자인 타임 코드 생성을 참조하세요.

런타임 템플릿은 템플릿 및 그 콘텐츠가 컴파일 시간에 결정되는 모든 애플리케이션에서 사용할 수 있습니다. 그러나 런타임 시 변경되는 템플릿에서 텍스트를 생성하는 Visual Studio 확장을 작성하려면 VS 확장에서 텍스트 변환 호출을 참조하세요.