贡献和配置
可以通过从某些基类派生来向 Visual Studio 公开扩展组件,并且可以通过定义某些属性并使用各种属性来配置它们。
Visual Studio 贡献
Visual Studio 扩展的目的是为 Visual Studio 提供 新功能。 这是通过扩展许多类之一来实现的,例如 Command
, ToolWindow
或 ExtensionPart
应用 VisualStudioContribution
属性。
本文引用 命令父 级示例扩展来说明参与和配置扩展组件的概念。
每个 VisualStudio.Extensibility 扩展插件必须至少提供一个 Extension
类:
namespace CommandParentingSample;
[VisualStudioContribution]
public class CommandParentingSampleExtension : Extension
{
/// <inheritdoc/>
protected override void InitializeServices(IServiceCollection serviceCollection)
{
base.InitializeServices(serviceCollection);
}
}
该 Extension
类是扩展的第一个实例化类,允许将自己的服务添加到 IServiceCollection
要用于依赖项注入的服务。
命令父级示例为 Visual Studio 贡献另一个类:a Command
:
[VisualStudioContribution]
internal class SampleCommand : Command
{
public SampleCommand()
{
}
...
扩展 VisualStudio.Extensibility SDK 提供的基类时,可以通过检查基类是否实现IVisualStudioContributionClass
(同时Extension
执行)Command
来了解是否应使用VisualStudioContribution
特性。
Visual Studio 贡献类是延迟实例化的单一实例:只创建一个实例,其创建延迟到 Visual Studio 需要与之交互(例如,用户首次调用某个 Command
实例时)。
VisualStudio.Extensibility 基础结构还允许你通过依赖项注入接收服务,作为 Visual Studio 贡献类的构造函数参数(请参阅 SDK 提供的用于注入的服务),包括添加到IServiceCollection
类InitializeServices
方法中的任何Extension
服务。
Visual Studio 通常需要唯一标识符与贡献相关联。 在大多数情况下,VisualStudio.Extensibility 基础结构使用 Visual Studio 贡献类的全名作为贡献标识符。 例如,上述类的 Extension
标识符为 CommandParentingSample.CommandParentingSampleExtension
. 你可能想要仔细选择 Visual Studio 贡献类的类型名称和命名空间,因为它们可能显示在 Visual Studio 日志和错误消息中。
配置 Visual Studio 贡献
大多数 Visual Studio 贡献类都需要或允许配置。 例如, Command
抽象类需要属性的 CommandConfiguration
实现,该属性至少指定命令的显示名称和(可选)其他属性(如其位置)。
[VisualStudioContribution]
internal class SampleCommand : Command
{
/// <inheritdoc />
public override CommandConfiguration CommandConfiguration => new("%CommandParentingSample.SampleCommand.DisplayName%")
{
Placements = new[]
{
// File in project context menu
CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id: 1072, priority: 0),
// Project context menu
CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id: 1026, priority: 0),
// Solution context menu
CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id: 1043, priority: 0),
},
};
...
CommandConfiguration
是编译 时常量,这意味着在生成扩展时计算其值,并将其包含在扩展清单中(extension.json
)。 Visual Studio 无需加载扩展本身即可读取扩展清单,从而提供更好的性能。
与普通属性相比,编译时常量 受到其他限制,例如,它们必须是只读的,其初始化代码不能包括对非静态成员或多语句命令性代码块的引用。 VisualStudio.Extensibility 生成工具强制实施这些限制,并生成错误消息,如下所示:
评估编译时常量 SampleCommand.CommandConfiguration 时遇到问题。 评估编译时常量值时不支持对用户定义的非静态成员的引用。
通常,扩展不应在运行时引用 编译时常量 配置属性。
由于编译时常量配置属性具有CompileTimeEvaluation
属性,因此可以轻松识别其定义。
public abstract class Command : ExecutableCommandHandler, IVisualStudioContributionClass
{
...
/// <summary>
/// Gets the configuration for this command. The value of this property is evaluated at compile time
/// when building the Visual Studio extension.
/// </summary>
[CompileTimeEvaluation]
public abstract CommandConfiguration CommandConfiguration { get; }
...
在极少数情况下,配置属性可能是可选的。 在某些情况下,可能需要在同一类上实现多个配置属性。 在扩展 ExtensionPart
和实现多个接口时,这很常见,每个接口都需要自己的配置属性。
独立配置属性
如上所述,Visual Studio 贡献类定义一个单一实例类,该类通常公开一个或多个 编译时常量 配置属性。 配置属性值保存为扩展元数据。
某些扩展性功能要求指定未绑定到任何类的扩展元数据,并且它本身有意义,或者其他配置将引用它。 一些示例包括菜单、工具栏和文档类型定义。 这可以通过将 VisualStudioContribution
属性应用于静态只读配置属性来实现。
Visual Studio 贡献属性可以放置在任何类中。
命令父级示例通过声明类型的ToolbarConfiguration
静态属性并将其标记为 VisualStudioContribution
来定义工具栏。
namespace CommandParentingSample;
internal static class ExtensionCommandConfiguration
{
[VisualStudioContribution]
public static ToolbarConfiguration ToolBar => new("%CommandParentingSample.ToolBar.DisplayName%")
{
Children = new[]
{
ToolbarChild.Command<SampleCommand>(),
},
};
}
Visual Studio 贡献属性也是 编译时常量 ,受前面讨论的相同限制的约束。
Visual Studio 贡献属性还可以引用另一个配置属性。 例如:
public static class MenuConfigurations
{
[VisualStudioContribution]
public static CommandGroupConfiguration MyCommandGroup => new(GroupPlacement.KnownPlacements.ExtensionsMenu)
{
Children = new GroupChild[]
{
GroupChild.Menu(MyMenu),
},
};
[VisualStudioContribution]
public static MenuConfiguration MyMenu => new("%MyMenu.DisplayName%")
{
Children = new[]
{
MenuChild.Command<MyCommand>(),
},
};
...
用于定义 Visual Studio 贡献属性的类型实现 IVisualStudioContributionProperty
接口,并在生成扩展时用 CompileTimeEvaluation
属性标记其值。
[CompileTimeEvaluation]
public sealed class DocumentTypeConfiguration : IVisualStudioContributionProperty ...
有关在运行时不引用 编译时常量 配置属性的指南也适用于 Visual Studio 贡献属性。
如果 Visual Studio 贡献属性需要唯一标识符,则 VisualStudio.Extensibility 基础结构会将其全名(包含类型全名和属性名称)用作标识符。 例如,此处讨论的工具栏配置的唯一标识符是 CommandParentingSample.ExtensionCommandConfiguration.ToolbarConfiguration
。