次の方法で共有


コントリビューションと構成

特定の基底クラスから派生することで、拡張機能コンポーネントを Visual Studio に公開できます。また、特定のプロパティを定義し、さまざまな属性を使用して構成することもできます。

Visual Studio の投稿

Visual Studio 拡張機能の目的は、Visual Studio に新しい機能を追加することです。 これを実現するには、CommandToolWindowExtensionPart などの多くのクラスのいずれかを拡張し、VisualStudioContribution 属性を適用します。

この記事では、Command Parenting サンプル拡張機能を参照して、拡張機能コンポーネントの寄与と構成の概念について説明します。

すべての VisualStudio.Extensibility 拡張機能は、少なくとも 1 つの Extension クラスを提供する必要があります。

namespace CommandParentingSample;

[VisualStudioContribution]
public class CommandParentingSampleExtension : Extension
{
    /// <inheritdoc/>
    protected override void InitializeServices(IServiceCollection serviceCollection)
    {
        base.InitializeServices(serviceCollection);
    }
}

Extension クラスは、拡張機能の最初のインスタンス化されたクラスであり、依存関係の挿入 に使用する IServiceCollection に独自のサービス追加できます。

Command Parentingのサンプルでは、別のクラス (Command) が Visual Studio に追加されます。

[VisualStudioContribution]
internal class SampleCommand : Command
{
    public SampleCommand()
    {
    }
    ...

VisualStudio.Extensibility SDK によって提供される基底クラスを拡張する場合は、基底クラスが IVisualStudioContributionClass を実装しているかどうかを確認することで、VisualStudioContribution 属性を使用することが期待されているかどうかを確認できます (ExtensionCommand の両方)。

Visual Studio のコントリビューション クラスは遅延してインスタンス化されるシングルトンです。インスタンスは 1 つだけ作成され、Visual Studio が操作する必要があるまで (たとえば、ユーザーが最初に Command を呼び出す場合など)、その作成は遅延されます。

VisualStudio.Extensibility インフラストラクチャを使用すると、依存関係の挿入を通じて、Visual Studio コントリビューション クラスのコンストラクター パラメーターとしてサービスを受け取ることもできます (VisualStudio.Extensibility 拡張機能 の依存関係の挿入参照)。これには、Extension クラスの InitializeServices メソッドで IServiceCollection に追加したサービスも含まれます。

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 コントリビューション クラスは、通常、1 つ以上の コンパイル時定数 構成プロパティを公開するシングルトン クラスを定義します。 構成プロパティの値は、拡張メタデータとして保存されます。

一部の拡張機能では、どのクラスにも関連付けられていない拡張メタデータを指定する必要があり、それ自体が意味を持つか、他の構成によって参照されることを意図しています。 いくつかの例として、メニュー、ツール バー、ドキュメントの種類の定義があります。 これは、静的な読み取り専用構成プロパティに 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です。