本主题介绍使用 Visual Studio 建模 SDK 创建的特定于域的语言(DSL)的定义和使用基本概念。
注释
安装 Visual Studio 的特定功能时,会自动安装文本模板转换 SDK 和 Visual Studio 建模 SDK。 有关更多详细信息,请参阅 此博客文章。
如果你不熟悉 DSL,我们建议你学习 DSL 工具实验室,你可以在此站点找到:可视化和建模 SDK
您可以使用领域特定语言做什么?
特定于域的语言是一种表示法,通常为图形,旨在用于特定目的。 相比之下,UML 等语言是常规用途。 在 DSL 中,可以定义模型元素的类型及其关系,以及它们在屏幕上的显示方式。
设计 DSL 后,可以将其分发为 Visual Studio 集成扩展 (VSIX) 包的一部分。 用户在 Visual Studio 中使用 DSL:
               
              
            
表示法只是 DSL 的一部分。 VSIX 包与表示法一起包括用户可应用的工具,以帮助他们编辑和生成模型的材料。
DSL 的主要应用程序之一是生成程序代码、配置文件和其他项目。 特别是在大型项目和产品线中,会创建多个产品变体,从 DSL 中生成许多可变方面可以显著提高可靠性,并对需求变更做出非常快速的响应。
本概述的其余部分是关于在Visual Studio中创建和使用特定于域的语言基本操作的演练。
先决条件
若要定义 DSL,必须已安装以下组件:
| 组件 | Link | 
|---|---|
| Visual Studio | http://go.microsoft.com/fwlink/?LinkId=185579 | 
| Visual Studio SDK | https://go.microsoft.com/fwlink/?linkid=2166172 | 
| 为 Visual Studio 建模 SDK | 
注释
文本模板转换组件作为 Visual Studio 扩展开发工作负载的一部分自动安装。 还可以从 Visual Studio 安装程序的 “单个组件 ”选项卡,在 SDK、库和框架 类别下安装它。 从“单个组件”选项卡安装建模 SDK 组件。
创建 DSL 解决方案
若要创建新的特定于域的语言,请使用 Domain-Specific 语言项目模板创建新的 Visual Studio 解决方案。
- 在“ 文件 ”菜单上,指向“ 新建”,然后单击“ 项目”。 
- 在 “项目类型”下,展开 “其他项目类型” 节点,然后单击“ 扩展性”。 
- 单击 Domain-Specific Language Designer。   
- 在“ 名称 ”框中,键入 FamilyTree。 单击 “确定” 。 - Domain-Specific 语言向导随即打开,并显示模板 DSL 解决方案的列表。 - 单击每个模板以查看说明, - 模板是一个有用的起点。 每个 DSL 都提供一个完整的功能,你可以根据需要进行编辑。 通常,选择最符合您想创建内容的模板。 
- 对于本演练,请选择 “最小语言 ”模板。 
- 在相应的向导页中输入 DSL 的文件扩展名。 这是文件包含您的 DSL 实例时将使用的扩展名。 - 选择在您的计算机或您打算安装 DSL 的任何计算机中未与任何应用程序关联的扩展名。 例如, docx 和 htm 是不可接受的文件扩展名。 
- 如果您输入的扩展被用作 DSL,向导将发出警告。 请考虑使用不同的文件扩展名。 还可以重置 Visual Studio SDK 实验实例以清除旧的实验设计器。 在 Windows “开始” 菜单中,键入 重置 Visual Studio,然后运行与 Visual Studio 版本匹配的“重置Microsoft Visual Studio 实验实例 ”命令。 
 
- 检查其他页面,然后单击“ 完成”。 - 生成包含两个项目的解决方案。 它们名为 Dsl 和 DslPackage。 此时会打开名为 DslDefinition.dsl 的关系图文件。 - 注释 - 在两个项目的文件夹中看到的大部分代码都是从 DslDefinition.dsl 生成的。 因此,对 DSL 所做的大多数修改都是在此文件中进行的。 
用户界面现在类似于下图。
               
              
            
此解决方案定义域特定的语言。 有关详细信息,请参阅 Domain-Specific 语言工具用户界面概述。
DSL 解决方案的重要部分
请注意新解决方案的以下方面:
- Dsl\DslDefinition.dsl 这是创建 DSL 解决方案时看到的文件。 解决方案中的所有代码都从此文件生成,你对 DSL 定义的大多数更改都在此处进行。 有关详细信息,请参阅 Working with the DSL Definition Diagram。 
- Dsl 项目 此项目包含定义特定于域的语言的代码。 
- DslPackage 项目 此项目包含允许在 Visual Studio 中打开和编辑 DSL 实例的代码。 
运行 DSL
创建 DSL 解决方案后,可以立即运行该解决方案。 稍后,可以逐步修改 DSL 定义,每次更改后再次运行解决方案。
试验 DSL
- 单击“转换所有模板”在解决方案资源管理器工具栏中。 这会从 DslDefinition.dsl 重新生成大部分源代码。 - 注释 - 每当更改 DslDefinition.dsl 时,都必须在重新生成解决方案之前单击“ 转换所有模板 ”。 可以自动化执行此步骤。 有关详细信息,请参阅 “如何自动转换所有模板”。 
- 按 F5 或在 “调试 ”菜单上,单击“ 开始调试”。 - DSL 已构建并安装在 Visual Studio 的实验性实例中。 - Visual Studio 的实验实例启动。 实验实例从注册表的单独子树中获取其设置,其中 Visual Studio 扩展注册用于调试。 Visual Studio 的正常实例无权访问其中注册的扩展。 
- 在 Visual Studio 的实验实例中,从解决方案资源管理器打开名为“测试”的模型文件。 - - 或 - - 右键单击调试项目,指向“添加”,然后单击“项”。 在 “添加项 ”对话框中,选择 DSL 的文件类型。 - 模型文件以空白关系图的形式打开。 - 工具箱将打开并显示适合关系图类型的工具。 
- 使用工具在关系图上创建形状和连接线。 - 要创建形状,请从样例形状工具拖动到图表上。 
- 若要连接两个形状,请单击示例连接线工具,单击第一个形状,然后单击第二个形状。 
 
- 单击形状的标签以更改它们。 
你的实验性 Visual Studio 将会类似于以下的示例:
               
              
            
模型的内容
作为 DSL 实例的文件的内容称为 模型。 该模型包含 模型元素 和元素之间的 链接 。 DSL 定义指定模型中可以存在的模型元素和链接的类型。 例如,在从最小语言模板创建的 DSL 中,有一种类型的模型元素和一种类型的链接。
DSL 定义可以指定模型在关系图上的显示方式。 可以从各种形状和连接线样式中进行选择。 可以指定某些形状显示在其他形状内。
编辑模型时,可以在 资源管理器 视图中以树的形式查看模型。 将形状添加到关系图时,模型元素也会显示在资源管理器中。 即使没有关系图,也可以使用资源管理器。
如果在 Visual Studio 的调试实例中看不到资源管理器,请在“视图”菜单上指向“其他窗口”,然后单击“<语言>资源管理器”。
DSL 的 API
DSL 生成一个 API,用于读取和更新属于 DSL 实例的模型。 API 的一个应用程序是从模型生成文本文件。 有关详细信息,请参阅 T4 文本模板设计时代码生成。
在调试解决方案中,打开扩展名为“.tt”的模板文件。 这些示例演示如何从模型生成文本,并允许你测试 DSL 的 API。 其中一个示例是用 Visual Basic 编写的,另一个是 Visual C# 编写的。
每个模板文件下方是生成的文件。 在解决方案资源管理器中展开模板文件,然后打开生成的文件。
模板文件包含一段短段代码,其中列出了模型中的所有元素。
生成的文件包含结果。
更改模型文件时,在重新生成文件后,将看到生成的文件中的相应更改。
更改模型文件后重新生成文本文件
- 在 Visual Studio 的实验实例中,保存模型文件。 
- 确保每个 .tt 文件中的文件名参数引用用于试验的模型文件。 保存 .tt 文件。 
- 单击转换所有模板在解决方案资源管理器的工具栏中。 - - 或 - - 右键单击要重新生成的模板,然后单击“ 运行自定义工具”。 
可以将任意数量的文本模板文件添加到项目中。 每个模板生成一个结果文件。
注释
更改 DSL 定义时,除非更新它,否则示例文本模板代码将不起作用。
有关详细信息,请参阅 从 Domain-Specific 语言生成代码 和 编写代码以自定义 Domain-Specific 语言。
自定义 DSL
如果要修改 DSL 定义,请关闭实验实例并在主 Visual Studio 实例中更新定义。
注释
修改 DSL 定义后,可能会在使用早期版本创建的测试模型中丢失信息。 例如,调试解决方案包含名为 Sample 的文件,其中包含一些形状和连接线。 开始开发 DSL 定义后,它们将不可见,保存文件时它们将会丢失。
你可以对 DSL 进行各种各样的扩展。 以下示例将为你提供可能性的印象。
每次更改后,保存 DSL 定义,单击解决方案资源管理器中的“转换所有模板”,然后按 F5 来试验更改后的 DSL。
重命名类型和工具
重命名现有域类和关系。 例如,从最小语言模板创建的 Dsl 定义开始,可以执行以下重命名操作,使 DSL 表示家谱。
重命名域类、关系和工具
- 在 DslDefinition 关系图中,将 ExampleModel 重命名为 FamilyTreeModel,ExampleElement 重命名为 Person,Targets 重命名为 Parents,将 Sources 重命名为 Children。 可以单击每个标签对其进行更改。   
- 重命名元素和连接器工具。 - 单击解决方案资源管理器下的选项卡,打开 DSL 资源管理器窗口。 如果看不到它,请在 “视图 ”菜单上指向 “其他 Windows ”,然后单击 “DSL 资源管理器”。 仅当 DSL 定义关系图为活动窗口时,DSL 资源管理器才可见。 
- 打开“属性”窗口并将其定位,以便同时查看 DSL 资源管理器和属性。 
- 在 DSL 浏览器中,展开 编辑器、 工具箱标签页、 <您的 DSL> 和 工具。 
- 单击 “ExampleElement”。 这是用于创建元素的工具箱项。 
- 在“属性”窗口中,将 Name 属性更改为 Person。 - 请注意, Caption 属性也会更改。 
- 同样,将 ExampleConnector 工具的名称更改为 ParentLink。 更改 Caption 属性,使其不是 Name 属性的副本。 例如,输入 父链接。 
 
- 重新生成 DSL。 - 保存 DSL 定义文件。 
- 单击解决方案资源管理器工具栏中的转换所有模板 
- 按 F5。 等到 Visual Studio 的实验实例出现。 
 
- 在 Visual Studio 试验实例的调试解决方案中,打开测试模型文件。 将元素从工具箱拖到它上。 请注意,DSL 资源管理器中的工具标题和类型名称已更改。 
- 保存模型文件。 
- 打开 .tt 文件,并将出现的旧类型和属性名称替换为新名称。 
- 确保 .tt 文件中指定的文件名指定测试模型。 
- 保存 .tt 文件。 打开生成的文件以查看在 .tt 文件中运行代码的结果。 验证它是否正确。 
将域属性添加到类
向域类添加属性,例如,表示人员的出生和死亡年份。
若要使新属性在关系图上可见,必须将 修饰器 添加到显示模型元素的形状。 还必须将属性映射到修饰器。
添加属性并显示它们
- 添加属性。 - 在 DSL 定义关系图中,右键单击 Person 域类,指向 “添加”,然后单击“ 域属性”。 
- 键入新的属性名称列表,例如 “出生 和 死亡”。 在每完成一个操作后按 Enter。 
 
- 添加修饰器,用于显示形状中的属性。 - 请跟随从 Person 域类延伸到图表另一侧的灰色线条。 这是图表元素映射。 它将领域类关联到形状类。 
- 右键单击此形状类,指向 “添加”,然后单击“ 文本修饰器”。 
- 添加两个修饰器,名称为 BirthDecorator 和 DeathDecorator。 
- 选择每个新的修饰器,然后在“属性”窗口中设置 “位置 ”字段。 这将确定域属性值将在形状上显示的位置。 例如,设置 InnerBottomLeft 和 InnerBottomRight。   
 
- 将修饰器映射到属性。 - 打开“DSL 详细信息”窗口。 它通常位于“输出”窗口旁边的选项卡中。 如果看不到它,请在 “视图 ”菜单上指向 “其他 Windows”,然后单击 “DSL 详细信息”。 
- 在 DSL 定义图中,单击将 Person 域类连接到形状类的线条。 
- 在 DSL 详细信息中,在 装饰器映射选项卡上,单击未映射装饰器的复选框。 在 “显示属性”中,选择要映射到的域属性。 例如,将 BirthDecorator 映射到 Birth。 
 
- 保存 DSL,单击“转换所有模板”,然后按 F5。 
- 在示例模型图中,验证你现在可以单击所选的位置,并在其中键入值。 此外,选择 人员 形状时,“属性”窗口将显示新的属性“出生和死亡”。 
- 在 .tt 文件中,可以添加用于获取每个人属性的代码。   
定义新类
可以将域类和关系添加到模型。 例如,可以创建一个新类来表示城镇,并创建一个新的关系来表示某个人住在某个城镇。
若要使模型关系图上的不同类型不同,可以将域类映射到不同类型的形状,或映射到具有不同几何图形和颜色的形状。
添加并显示新域类
- 添加域类并将其设为模型根的子级。 - 在 DSL 定义关系图中,单击 嵌入关系 工具,单击根类 FamilyTreeModel,然后单击关系图的空部分。 - 此时会显示一个新的域类,该类连接到具有嵌入关系的 FamilyTreeModel。 - 设置其名称,例如 Town。 - 注释 - 除模型根目录以外的每个域类都必须是至少一个嵌入关系的目标,或者它必须继承自作为嵌入目标的类。 因此,使用嵌入关系工具创建域类通常很方便。 
- 将域属性添加到新类,例如 Name。 
 
- 添加 Person 和 Town 之间的引用关系。 - 单击 “引用关系 ”工具,单击“人员”,然后单击“城镇”。   - 注释 - 引用关系表示从模型树的一部分到另一部分的交叉引用。 
 
- 添加形状以表示模型关系图上的城镇。 - 将 “几何图形” 从工具箱拖动到关系图并重命名它,例如 TownShape。 
- 在“属性”窗口中,设置新形状的外观字段,例如填充颜色和几何图形。 
- 添加修饰器以显示该镇的名称,并将其重命名为 NameDecorator。 设置其 Position 属性。 
 
- 将 Town 域类映射到 TownShape。 - 单击 “关系图元素映射 ”工具,然后单击“城镇”域类,然后单击“TownShape”形状类。 
- 在 “DSL 详细信息” 窗口的 “修饰器映射” 选项卡中选中地图连接器后,选中 NameDecorator 并将 “显示属性” 设置为 Name。 
 
- 创建连接器以显示 Person 和 Towns 之间的关系。 - 将连接器从工具箱拖到关系图。 重命名它并设置其外观属性。 
- 使用 “关系图元素映射 ”工具将新连接器链接到 Person 和 Town 之间的关系。   
 
- 创建用于创建新 Town 的元素工具。 - 在 DSL 资源管理器中,展开 编辑器 ,然后展开 工具箱选项卡。 
- 右键单击 <DSL> ,然后单击“ 添加新元素工具”。 
- 设置新工具的 Name 属性,并将其 类 属性设置为 Town。 
- 设置 工具箱图标 属性。 单击 “ ”、“ 在 ”文件名 “字段中,选择一个图标文件。 
 
- 创建连接器工具,用于在城镇和人员之间建立链接。 - 右键单击 <DSL> ,然后单击“ 添加新连接器工具”。 
- 设置新工具的 Name 属性。 
- 在 ConnectionBuilder 属性中,选择包含 Person-Town 关系名称的生成器。 
- 设置 工具箱图标。 
 
- 保存 DSL 定义,单击“ 转换所有模板”,然后按 F5。 
- 在 Visual Studio 的实验实例中,打开测试模型文件。 使用新工具创建城镇,并在城镇与人员之间建立链接。 请注意,只能在正确的元素类型之间创建链接。 
- 创建代码,列出每个人居住的城镇。 文本模板是可以运行此类代码的位置之一。 例如,可以在调试解决方案中修改现有 Sample.tt 文件,使其包含以下代码: - <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" debug="true" #> <#@ output extension=".txt" #> <#@ FamilyTree processor="FamilyTreeDirectiveProcessor" requires="fileName='Sample.ftree'" #> <# foreach (Person person in this.FamilyTreeModel.People) { #> <#= person.Name #><#if (person.Town != null) {#> of <#= person.Town.Name #> <#}#> <# foreach (Person child in person.Children) { #> <#= child.Name #> <# } } #>- 保存 *.tt 文件时,它将创建一个包含人员及其居住地列表的附属文件。 有关详细信息,请参阅 从 Domain-Specific 语言生成代码。 
验证和命令
可以通过添加验证约束来进一步开发此 DSL。 这些约束是可以定义的方法,确保模型处于正确的状态。 例如,可以定义一个约束,以确保孩子的出生日期比其父母晚。 如果 DSL 用户尝试保存破坏任何约束的模型,验证功能将显示警告。 有关详细信息,请参阅 Domain-Specific 语言中的验证。
还可以定义用户可以调用的菜单命令。 命令可以修改模型。 它们还可以与 Visual Studio 中的其他模型和外部资源进行交互。 有关详细信息,请参阅 “如何:修改标准菜单命令”。
部署 DSL
若要允许其他用户使用特定于域的语言,请分发 Visual Studio 扩展 (VSIX) 文件。 生成 DSL 解决方案时会创建此项。
在解决方案的 bin 文件夹中找到 .vsix 文件。 将其复制到要安装它的计算机上。 在该计算机上,双击 VSIX 文件。 DSL 可在该计算机上的 Visual Studio 的所有实例中使用。
可以使用相同的过程在自己的计算机上安装 DSL,这样就不必使用 Visual Studio 的实验实例。
有关详细信息,请参阅 部署 Domain-Specific 语言解决方案。
删除旧的实验 DSL
如果已创建不再需要的实验 DSL,可以通过重置 Visual Studio 实验实例将其从计算机中删除。
这将从计算机中删除所有实验 DSL 和其他实验 Visual Studio 扩展。 这些扩展已在调试模式下执行。
此过程不会删除通过执行 VSIX 文件完全安装的 DSL 或其他 Visual Studio 扩展。
重置 Visual Studio 实验实例
- 在 Windows “开始” 菜单中,键入 重置 Visual Studio,然后运行与 Visual Studio 版本匹配的“重置Microsoft Visual Studio 实验实例 ”命令。 
- 重新生成任何实验性 DSL 或其他仍要使用的实验性的 Visual Studio 扩展。