Partilhar via


Acessando modelos a partir de modelos de texto

Usando modelos de texto, você pode criar arquivos de relatório, arquivos de código fonte e outros arquivos de texto que são baseados em modelos de linguagem específica de domínio.Para obter informações básicas sobre modelos de texto, consulte Modelos de texto T4 e de geração de código.Os modelos de texto funcionarão no modo experimental quando você está depurando seu DSL e também funcionarão em um computador em que você implantou o DSL.

ObservaçãoObservação

Quando você cria uma solução DSL, a amostra de modelo de texto *.tt arquivos são gerados no projeto de depuração.Quando você altera os nomes das classes de domínio, esses modelos deixarão de funcionar.No entanto, eles incluem as diretivas básicas que você precisa e fornecem exemplos que você pode atualizar para corresponder ao seu DSL.

Para acessar um modelo a partir de um modelo de texto:

  • Defina a propriedade de herdar da diretriz de modelo para ModelingTextTransformation.Fornece acesso ao armazenamento.

  • Especifique os processadores de diretriz para DSL que você deseja acessar.Isso carrega os assemblies para seu DSL para que você possa usar suas classes de domínio, propriedades e relacionamentos no código do seu modelo de texto.Ele também carrega o arquivo de modelo que você especificar.

A .tt arquivo semelhante ao exemplo a seguir é criado no projeto depuração quando você cria um novo Visual Studio solução a partir do modelo de idioma de um mínimo de DSL.

<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" #>
<#@ output extension=".txt" #>
<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1'" #>

This text will be output directly.

This is the name of the model: <#= this.ModelRoot.Name #>

Here is a list of elements in the model:
<#
  // When you change the DSL Definition, some of the code below may not work.
  foreach (ExampleElement element in this.ExampleModel.Elements)
  {#>
<#= element.Name #>
<#    
  }
#>

Observe os seguintes pontos sobre este modelo:

  • O modelo pode usar as classes de domínio, propriedades e relacionamentos que você definiu na definição de DSL.

  • O modelo carrega o arquivo de modelo que você especificar na requires propriedade.

  • Uma propriedade em this contém o elemento raiz.A partir daí, o seu código pode navegar para outros elementos do modelo.O nome da propriedade geralmente é o mesmo que a classe de domínio raiz de seu DSL.Neste exemplo, é this.ExampleModel.

  • Embora a linguagem na qual os fragmentos de código são escritos for C#, você pode gerar o texto de qualquer tipo.Você também pode escrever o código Visual Basic , adicionando a propriedade language="VB" para o template diretiva.

  • Para depurar o modelo, adicione debug="true" para o template diretiva.O modelo será aberto em outra instância do Visual Studio se ocorrer uma exceção.Se você deseja separar o depurador em um ponto específico no código, a instrução de inserçãoSystem.Diagnostics.Debugger.Break();

    Para obter mais informações, consulte Depuração de um modelo de texto T4.

Sobre o processador de diretriz de DSL

O modelo pode usar as classes de domínio que você definiu na sua definição de DSL.Isso é trazido por uma diretiva que geralmente aparece perto do início do modelo.No exemplo anterior, é o seguinte.

<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1'" #>

O nome da diretiva ( MyLanguage, neste exemplo) é derivado do nome do seu DSL.Ele chama um processador de diretriz que é gerado como parte de seu DSL.Você pode encontrar o seu código-fonte em Dsl\GeneratedCode\DirectiveProcessor.cs.

O processador de diretriz de DSL executa duas tarefas principais:

  • Insere efetivamente assembly e importar diretivas no modelo que faz referência a seu DSL.Isso permite que você use suas classes de domínio no código de modelo.

  • Ele carrega o arquivo que você especificar na requires parâmetro e define uma propriedade na this que se refere ao elemento raiz do modelo carregado.

Validando o modelo antes de executar o modelo

Você pode fazer com que o modelo a ser validado antes que o modelo seja executado.

<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1';validation='open|load|save|menu'" #>

Observe que:

  1. O filename e validation parâmetros são separados com ";" e deve haver outros separadores ou espaços.

  2. A lista de categorias de validação determina quais métodos de validação serão executados.Várias categorias devem ser separadas por "|" e deve haver outros separadores ou espaços.

Se um erro for encontrado, ele será relatado na janela de erros e o arquivo de resultado conterá uma mensagem de erro.

Acessando vários modelos a partir de um modelo de texto

ObservaçãoObservação

Esse método permite que você ler vários modelos no mesmo modelo, mas não oferece suporte a referências de ModelBus.Para ler os modelos que são interlinked por ModelBus referências, consulte Usando o ModelBus de Visual Studio em um modelo de texto.

Se você deseja acessar mais de um modelo a partir do mesmo modelo de texto, você deve chamar o processador de diretriz gerado uma vez para cada modelo.Você deve especificar o nome do arquivo de cada modelo de requires parâmetro.Você deve especificar os nomes que você deseja usar para a classe de domínio raiz na provides parâmetro.Você deve especificar valores diferentes para o provides parâmetros de cada uma das chamadas diretriz.Por exemplo, suponha que você tem três arquivos de modelo chamados Library.xyz, School.xyz e Work.xyz.Para acessá-los a partir do mesmo modelo de texto, você deve escrever três chamadas diretriz que se parecem com os seguintes.

<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='Library.xyz'" provides="ExampleModel=LibraryModel" #>
<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='School.xyz'" provides="ExampleModel=SchoolModel" #>
<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='Work.xyz'" provides="ExampleModel=WorkModel" #>
ObservaçãoObservação

Esse código de exemplo é para um idioma que se baseia no modelo de solução de idioma mínima.

Para acessar os modelos em seu modelo de texto, você agora pode escrever um código semelhante ao código no exemplo a seguir.

<#
foreach (ExampleElement element in this.LibraryModel.Elements)
...
foreach (ExampleElement element in this.SchoolModel.Elements)
...
foreach (ExampleElement element in this.WorkModel.Elements)
...
#>
<#
For Each element As ExampleElement In Me.LibraryModel.Elements
...
For Each element As ExampleElement In Me.SchoolModel.Elements
...
For Each element As ExampleElement In Me.WorkModel.Elements
...
#>

Carregar modelos dinamicamente

Se você quiser determinar em tempo de execução quais modelos para carregar, você pode carregar um arquivo de modelo dinamicamente no seu código de programa, em vez de usar a diretiva de DSL específicos.

No entanto, uma das funções da diretiva específicas DSL é importar o namespace DSL, para que o código do modelo pode usar as classes de domínio definidas no que DSL.Porque você não estiver usando a diretiva, você deve adicionar <assembly> e <import> diretivas para todos os modelos que você pode carregar.Isso é fácil se os modelos diferentes que você pode carregar todas as instâncias do mesmo DSL.

Para carregar o arquivo, o método mais eficaz é utilizar Visual Studio ModelBus.Um cenário típico, seu modelo de texto irá usar uma diretiva de DSL específico para carregar o primeiro modelo da maneira usual.Esse modelo conteria ModelBus referências para outro modelo.Você pode usar ModelBus para abrir o modelo de referência e acessar um determinado elemento.Para obter mais informações, consulte Usando o ModelBus de Visual Studio em um modelo de texto.

Em um cenário menos usual, você talvez queira abrir um arquivo de modelo para os quais você tem apenas um nome de arquivo, e que não estejam na atual Visual Studio project.Nesse caso, você pode abrir o arquivo usando a técnica descrita no Como: abrir um modelo de arquivo no código de programa.

Gerar vários arquivos a partir de um modelo

Se você deseja gerar um vários arquivos – por exemplo, para gerar um arquivo separado para cada elemento em um modelo, há várias abordagens possíveis.Por padrão, somente um arquivo é produzido a partir de cada arquivo de modelo.

Bb126577.collapse_all(pt-br,VS.110).gifA divisão de um arquivo longo

Nesse método, você pode usar um modelo para gerar um único arquivo, separado por um delimitador.Em seguida, você deve dividir o arquivo em suas partes.Há dois modelos, um para gerar o arquivo único e o outro para dividi-lo.

LoopTemplate.t4gera o arquivo único longos.Observe que a sua extensão de arquivo é ".t4", porque ele não deve ser processado diretamente quando você clica em Transformar todos os modelos de.Este modelo tem um parâmetro que especifica a seqüência de caracteres de delimitador que separa os segmentos:

<#@ template ninherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" #>
<#@ parameter name="delimiter" type="System.String" #>
<#@ output extension=".txt" #>
<#@ MyDSL processor="MyDSLDirectiveProcessor" requires="fileName='SampleModel.mydsl1';validation='open|load|save|menu'" #>
<#
  // Create a file segment for each element:
  foreach (ExampleElement element in this.ExampleModel.Elements) 
  { 
    // First item is the delimiter:
#>
<#= string.Format(delimiter, element.Id) #>

   Element: <#= element.Name #>
<#
   // Here you generate more content derived from the element.
  }
#>

LoopSplitter.ttinvoca LoopTemplate.t4e, em seguida, divide o arquivo resultante em seus segmentos.Observe que este modelo não tem como um modelo de modelagem, porque ele não ler o modelo.

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="System.Runtime.Remoting.Messaging" #>
<#@ import namespace="System.IO" #>

<#
  // Get the local path:
  string itemTemplatePath = this.Host.ResolvePath("LoopTemplate.t4");
  string dir = Path.GetDirectoryName(itemTemplatePath);

  // Get the template for generating each file:
  string loopTemplate = File.ReadAllText(itemTemplatePath);

  Engine engine = new Engine();
  
  // Pass parameter to new template:
  string delimiterGuid = Guid.NewGuid().ToString();
  string delimiter = "::::" + delimiterGuid + ":::";
  CallContext.LogicalSetData("delimiter", delimiter + "{0}:::"); 
  string joinedFiles = engine.ProcessTemplate(loopTemplate, this.Host);

  string [] separateFiles = joinedFiles.Split(new string [] {delimiter}, StringSplitOptions.None);

  foreach (string nameAndFile in separateFiles) 
  { 
     if (string.IsNullOrWhiteSpace(nameAndFile)) continue;
     string[] parts = nameAndFile.Split(new string[]{":::"}, 2, StringSplitOptions.None);
     if (parts.Length < 2) continue;
#>
 Generate: [<#= dir #>] [<#= parts[0] #>]
<#
     // Generate a file from this item:
     File.WriteAllText(Path.Combine(dir, parts[0] + ".txt"), parts[1]);  
  }
#>