Uzyskiwanie dostępu do modeli z szablonów tekstu
Przy użyciu szablonów tekstu, można utworzyć raport pliki, pliki kodu źródłowego i inne pliki tekstowe, które są oparte na modelach języka specyficzne dla domeny.Podstawowe informacje na temat szablonów tekstu, zobacz Kod generacji i szablony tekst T4.Szablony tekst będzie działać w trybie doświadczalnych podczas debugowania modem DSL i będzie również działać na komputerze, na którym została wdrożona DSL.
[!UWAGA]
Podczas tworzenia rozwiązania DSL, przykładowy tekst szablon *.tt pliki są generowane w projekcie debugowania.Po zmianie nazwy klas domeny szablony te nie będą działać.Niemniej jednak zawierają one podstawowych dyrektyw, które są potrzebne i zawierają przykłady, które można aktualizować, aby dopasować linii DSL.
Dostęp do modelu z szablonu tekstu:
Ustaw właściwość Dziedzicz szablon dyrektywy ModelingTextTransformation.Zapewnia to dostęp do magazynu.
Określ procesorów w dyrektywie DSL, do którego chcesz uzyskać dostęp.Ładuje zestawów do linii DSL, tak, aby w kodzie szablonu tekstu można użyć jego domeny klas, właściwości i relacji.Również ładuje plik modelu, który określisz.
A .tt jest tworzony plik podobny do następującego przykładu w projekcie debugowanie, podczas tworzenia nowego Visual Studio roztwór z szablonu języka minimalne 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 #>
<#
}
#>
Zwróć uwagę następujące kwestie dotyczące tego szablonu:
Domeny klas, właściwości i relacji, które są określone w definicji DSL, można użyć szablonu.
Szablon ładuje plik modelu, który określony w requires właściwości.
Właściwość w this zawiera element główny.Stamtąd kodu można przechodzić do innych elementów modelu.Nazwa właściwości jest zwykle klasy domeny katalogu głównego linii DSL.W tym przykładzie jest this.ExampleModel.
Chociaż jest język, w którym zapisywane są fragmenty kodu C#, można generować tekst dowolnego rodzaju.Można też napisać kod w Visual Basic przez dodanie właściwości language="VB" do template dyrektywy.
Debugowanie szablonu, należy dodać debug="true" do template dyrektywy.Szablon zostanie otwarty w innym wystąpieniu programu Visual Studio , jeśli wystąpi wyjątek.Jeśli chcesz podzielić na debugera w określonym miejscu w kodzie, Wstaw instrukcjiSystem.Diagnostics.Debugger.Break();
Aby uzyskać więcej informacji, zobacz Debugowanie szablonu tekst T4.
O procesor dyrektywa DSL
Szablon można skorzystać z klas domeny, zdefiniowanego w Państwa definicji DSL.To jest spowodowanych dyrektywy, która pojawia się zazwyczaj w pobliżu początku szablonu.W poprzednim przykładzie jest następująca.
<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1'" #>
Nazwa dyrektywy ( MyLanguage, w tym przykładzie) pochodzi od nazwy linii DSL.Wywołuje to procesora dyrektywa generowany jako część linii DSL.Można znaleźć jego kod źródłowy w Dsl\GeneratedCode\DirectiveProcessor.cs.
Procesor dyrektywa DSL wykonuje dwa podstawowe zadania:
Wstawia skutecznie dyrektyw Zgromadzenia i przywozu, do szablonu, który odwołuje się do linii DSL.Dzięki temu można użyć klasy użytkownika domeny w kodzie szablonu.
Ładuje określony w pliku requires parametr i ustawia właściwość this odwołujący się do elementu głównego modelu ładowane.
Sprawdzanie poprawności modelu przed uruchomieniem tego szablonu
Można spowodować, że model do szablonu jest wykonywane, można sprawdzić poprawności.
<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1';validation='open|load|save|menu'" #>
Należy zauważyć, że:
filename i validation parametrów są rozdzielane z ";" i musi istnieć nie separatorów lub spacji.
Lista sprawdzania poprawności kategorii określa metody sprawdzania poprawności, które będą wykonywane.Wiele kategorii powinny być oddzielone z "|" i musi istnieć nie separatorów lub spacji.
Jeśli zostanie znaleziony błąd, zostanie ona zgłoszona w oknie błędów i plik wynik będzie zawierać komunikat o błędzie.
Dostęp do wielu modeli z szablonu tekstu
[!UWAGA]
Metoda ta pozwala odczytać wiele modeli, w tym samym szablonie, ale nie obsługuje odwołań ModelBus.Aby odczytać modeli, które są ze sobą powiązane przez ModelBus odniesienia, zobacz W szablonie tekstu przy użyciu programu Visual Studio ModelBus.
Chcesz uzyskać dostęp do więcej niż jednego modelu z tego samego szablonu tekstu, musisz wywołać generowanych procesora w dyrektywie jeden raz dla każdego modelu.Należy określić nazwę pliku każdego modelu w requires parametru.Należy określić nazwy, które chcesz użyć dla klasy domeny katalogu głównego w provides parametru.Należy określić różne wartości dla provides parametry w każdej dyrektywie wywołań.Na przykład załóżmy, że trzy pliki modelu o nazwie Library.xyz, School.xyz i Work.xyz.Do nich dostęp z tego samego szablonu tekstu, należy napisać trzy wywołania dyrektywy, które przypominają następujące z nich.
<#@ 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" #>
[!UWAGA]
Ten przykładowy kod jest dla języka, który jest oparty na szablonie roztwór minimalne języka.
Aby uzyskać dostęp do modeli w szablonie tekstu, można teraz napisać kod podobny do kodu w następującym przykładzie.
<#
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
...
#>
Ładowanie dynamiczne modeli
Jeśli chcesz określić w czasie wykonywania, które modele do ładowania pliku modelu można załadować dynamicznie w kodzie programu, zamiast stosowania dyrektywy szczególne DSL.
Jednak jedna z funkcji dyrektywy szczególne DSL jest importować nazw DSL, tak, że kod szablonu można użyć klasy domeny zdefiniowane w tym DSL.Ponieważ dyrektywa nie jest używany, należy dodać <assembly> i <import> dyrektyw dla wszystkich modeli, które mogą być ładowane.Jest to łatwe, jeśli różnych modeli, które mogą być ładowane są instancjami tej samej linii DSL.
Aby załadować plik, najbardziej skuteczną metodą jest użycie Visual Studio ModelBus.W typowym scenariuszu szablonu tekst użyje dyrektywy szczególne DSL załadować pierwszy model w zwykły sposób.Model ten zawierałby ModelBus odwołania do innego modelu.Aby otworzyć model, do którego istnieje odwołanie i dostępu do określonego elementu, można użyć ModelBus.Aby uzyskać więcej informacji, zobacz W szablonie tekstu przy użyciu programu Visual Studio ModelBus.
W scenariuszu mniej zwykłymi, warto otworzyć plik modelu, do którego masz tylko nazwę pliku, i które nie mogą być w bieżącym Visual Studio projektu.W takim przypadku można otworzyć plik przy użyciu techniki opisane w Jak: Otwórz Model z pliku kodu programu.
Generowanie wielu plików z szablonu
Jeśli chcesz wygenerować kilka plików — na przykład wygenerować osobny plik dla każdego elementu w modelu, istnieją kilka możliwych podejść.Domyślnie tylko jeden plik jest wyprodukowany z każdego pliku szablonu.
Długie dzielenie
W tej metodzie jest używany szablon, aby wygenerować pojedynczy plik, oddzielonych ogranicznikiem.Następnie można podzielić go na jego części.Istnieją dwa szablony, jeden do generowania pojedynczy plik, a drugi do podziału.
LoopTemplate.t4generuje długich pojedynczy plik.Zauważ, że jej rozszerzenie pliku jest ".t4", ponieważ jej nie powinny być przetwarzane bezpośrednio po kliknięciu przycisku Transform wszystkie szablony.Ten szablon ma parametr określający ciąg ogranicznik oddziela segmentów:
<#@ 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.ttwywołuje LoopTemplate.t4, a następnie dzieli wynikowy plik na jej segmenty.Należy zauważyć, że ten szablon nie ma być Szablon modelowania, ponieważ nie odczytuje modelu.
<#@ 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]);
}
#>