次の方法で共有


System.Runtime.Versioning.ComponentGuaranteesAttribute クラス

この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。

ComponentGuaranteesAttributeは、コンポーネントとクラス ライブラリの開発者が、ライブラリのコンシューマーが複数のバージョンにわたって期待できる互換性のレベルを示すために使用されます。 これは、ライブラリまたはコンポーネントの将来のバージョンが既存のクライアントを中断しないことを保証するレベルを示します。 クライアントは、バージョン間の安定性を確保するために、独自のインターフェイスを設計する際の支援として、 ComponentGuaranteesAttribute を使用できます。

共通言語ランタイム (CLR) では、この属性は使用されません。 その値は、コンポーネント作成者の意図を正式に文書化することです。 コンパイル時ツールでは、これらの宣言を使用して、宣言された保証を損なうコンパイル時エラーを検出することもできます。

互換性のレベル

ComponentGuaranteesAttributeでは、次のレベルの互換性がサポートされています。これは、ComponentGuaranteesOptions列挙体のメンバーによって表されます。

  • バージョン間の互換性はありません (ComponentGuaranteesOptions.None)。 クライアントは、将来のバージョンが既存のクライアントを中断することを期待できます。 詳細については、この記事の後半の「 互換性なし」 セクションを参照してください。

  • side-by-side version-to-version compatibility (ComponentGuaranteesOptions.SideBySide)。 同じアプリケーション ドメインに複数のバージョンのアセンブリが読み込まれるときに、コンポーネントが動作するようにテストされています。 一般に、将来のバージョンは互換性を損なう可能性があります。 ただし、破壊的変更が行われると、古いバージョンは変更されませんが、新しいバージョンと共に存在します。 サイド バイ サイド実行は、重大な変更が行われたときに既存のクライアントを動作させる方法です。 詳細については、この記事で後述するサイド バイ サイド互換性 のセクションを参照してください。

  • 安定したバージョン間互換性 (ComponentGuaranteesOptions.Stable)。 今後のバージョンではクライアントを中断する必要はありません。また、サイド バイ サイドの実行は必要ありません。 ただし、クライアントが誤って破損した場合は、サイド バイ サイド実行を使用して問題を解決できる可能性があります。 詳細については、「 安定した互換性 」セクションを参照してください。

  • Exchange のバージョン間の互換性 (ComponentGuaranteesOptions.Exchange)。 将来のバージョンがクライアントを壊さないよう、特別な注意が払われます。 クライアントは、相互に独立して展開されている他のアセンブリとの通信に使用されるインターフェイスのシグネチャで、これらの型のみを使用する必要があります。 これらの型の 1 つのバージョンのみが特定のアプリケーション ドメインに存在することが予想されます。つまり、クライアントが中断した場合、サイド バイ サイド実行では互換性の問題を解決できません。 詳細については、「 Exchange の種類の互換性 」セクションを参照してください。

以降のセクションでは、各レベルの保証について詳しく説明します。

互換性なし

コンポーネントを ComponentGuaranteesOptions.None としてマークすると、プロバイダーは互換性に関する保証を行いません。 クライアントは、公開されているインターフェイスに依存しないようにする必要があります。 このレベルの互換性は、試験的な型、または一般に公開されているが、常に同時に更新されるコンポーネントのみを対象とする型に役立ちます。 None は、このコンポーネントを外部コンポーネントで使用しないことを明示的に示します。

Side-by-side 互換性

コンポーネントを ComponentGuaranteesOptions.SideBySide としてマークすると、複数のバージョンのアセンブリが同じアプリケーション ドメインに読み込まれるときに、コンポーネントが動作するようにテストされていることを示します。 重大な変更は、バージョン番号が大きいアセンブリに対して行われる限り許可されます。 アセンブリの古いバージョンにバインドされているコンポーネントは、引き続き古いバージョンにバインドすることが想定されており、他のコンポーネントは新しいバージョンにバインドできます。 以前のバージョンを破壊的に変更することで、 SideBySide と宣言されているコンポーネントを更新することもできます。

安定した互換性

型を ComponentGuaranteesOptions.Stable としてマークすると、型はバージョン間で安定している必要があります。 ただし、安定した型の side-by-side バージョンが同じアプリケーション ドメインに存在する場合もあります。

安定した型は、高いバイナリ互換性バーを維持します。 このため、プロバイダーは安定した型に重大な変更を加えないようにする必要があります。 次の種類の変更が可能です。

  • プライベート インスタンス フィールドを型に追加したり、型からフィールドを削除したりする場合は、シリアル化の形式が損なわれません。
  • シリアル化できない型をシリアル化可能な型に変更する。 (ただし、シリアル化可能な型をシリアル化できない型に変更することはできません)。
  • メソッドからより派生した新しい例外をスローする。
  • メソッドのパフォーマンスの向上。
  • 変更が大部分のクライアントに悪影響を及ぼさない限り、戻り値の範囲を変更します。
  • ビジネス上の正当な理由が高く、悪影響を受けるクライアントの数が少ない場合に、重大なバグを修正します。

安定したコンポーネントの新しいバージョンは既存のクライアントを中断することは想定されていないため、一般に、アプリケーション ドメインには安定したコンポーネントの 1 つのバージョンのみが必要です。 ただし、安定した型は、すべてのコンポーネントが同意する既知の交換の種類として使用されないため、これは要件ではありません。 したがって、安定したコンポーネントの新しいバージョンが誤ってコンポーネントを中断し、他のコンポーネントに新しいバージョンが必要な場合は、古いコンポーネントと新しいコンポーネントの両方を読み込むことで問題を解決できる可能性があります。

Stable は、 Noneよりも強力なバージョン互換性保証を提供します。 これは、複数バージョンのコンポーネントの一般的な既定値です。

Stable は、 SideBySideと組み合わせることができます。これは、コンポーネントが互換性を損なわないが、特定のアプリケーション ドメインに複数のバージョンが読み込まれるときに動作するようにテストされることを示します。

型またはメソッドが Stableとしてマークされた後、 Exchangeにアップグレードできます。 ただし、 Noneにダウングレードすることはできません。

Exchange の種類の互換性

型を ComponentGuaranteesOptions.Exchange としてマークすると、 Stableよりもバージョン互換性が保証され、すべての型の中で最も安定したものに適用する必要があります。 これらの型は、すべてのコンポーネント境界 (任意のバージョンの CLR またはコンポーネントまたはアプリケーションの任意のバージョン) と空間 (クロスプロセス、1 つのプロセスでの CLR 間、1 つの CLR 内のアプリケーション間ドメイン) の両方で、独立して構築されたコンポーネント間の交換に使用することを目的としています。 交換の種類に重大な変更が加えられた場合、型の複数のバージョンを読み込んで問題を解決することはできません。

Exchange の種類は、問題が非常に深刻な場合 (重大なセキュリティの問題など) または破損の確率が非常に低い場合 (つまり、コードが依存関係を取ることができなかったランダムな方法で動作が既に壊れている場合) にのみ変更する必要があります。 交換の種類に対して次の種類の変更を行うことができます。

  • 新しいインターフェイス定義の継承を追加します。

  • 新しく継承されたインターフェイス定義のメソッドを実装する新しいプライベート メソッドを追加します。

  • 新しい静的フィールドを追加します。

  • 新しい静的メソッドを追加します。

  • 新しい非仮想インスタンス メソッドを追加します。

以下は破壊的変更と見なされ、プリミティブ型では使用できません。

  • シリアル化形式の変更。 バージョン トレラントなシリアル化が必要です。

  • プライベート インスタンス フィールドの追加または削除。 これにより、型のシリアル化形式が変更され、リフレクションを使用するクライアント コードが破損するリスクがあります。

  • 型のシリアル化可能性の変更。 シリアル化できない型はシリアル化できない場合があります。逆も可能です。

  • メソッドから異なる例外をスローする。

  • メンバー定義がこの可能性を引き出し、クライアントが不明な値を処理する方法を明確に示す場合を除き、メソッドの戻り値の範囲を変更します。

  • ほとんどのバグを修正します。 型のコンシューマーは、既存の動作に依存します。

コンポーネント、型、またはメンバーが Exchange 保証でマークされた後は、 Stable または Noneに変更することはできません。

通常、交換型は基本型 (.NET の Int32String など) と、パブリック インターフェイスでよく使用されるインターフェイス ( IList<T>IEnumerable<T>IComparable<T>など) です。

Exchange の種類では、互換性 Exchange マークされている他の型のみが公開される場合があります。 また、交換の種類は、変更されやすい Windows API の動作に依存できません。

コンポーネントの保証

次の表は、コンポーネントの特性と使用方法が互換性の保証にどのように影響するかを示しています。

コンポーネントの特性 交換 安定 Side-by-Side 無し
個別にバージョン管理するコンポーネント間のインターフェイスで使用できます。 Y N N N
個別にバージョン管理するアセンブリで (プライベートに) 使用できます。 Y Y Y N
1 つのアプリケーション ドメインに複数のバージョンを含めることができます。 N Y Y Y
破壊的変更を加えることができます N N Y Y
アセンブリの特定の複数のバージョンを一緒に読み込むことができるようにテストします。 N N Y N
破壊的変更を行うことができます。 N N N Y
非常に安全な非破壊的サービスの変更を行うことができます。 Y Y Y Y

属性を適用する

アセンブリ、型、または型メンバーに ComponentGuaranteesAttribute を適用できます。 そのアプリケーションは階層構造になっています。 つまり、既定では、アセンブリ レベルで属性の Guarantees プロパティによって定義される保証によって、アセンブリ内のすべての型とそれらの型のすべてのメンバーの保証が定義されます。 同様に、保証が型に適用される場合、既定では、型の各メンバーにも適用されます。

この継承された保証は、個々の型と型のメンバーに ComponentGuaranteesAttribute を適用することでオーバーライドできます。 ただし、既定値をオーバーライドする保証は、保証を弱めることもできます。彼らはそれを強化することはできません。 たとえば、アセンブリが None 保証でマークされている場合、その型とメンバーは互換性の保証を受けず、アセンブリ内の型またはメンバーに適用されるその他の保証は無視されます。

保証をテストする

Guarantees プロパティは、FlagsAttribute属性でマークされたComponentGuaranteesOptions列挙体のメンバーを返します。 これは、不明な可能性があるフラグをマスクして、関心のあるフラグをテストする必要があることを意味します。 たとえば、次の例では、型が Stableとしてマークされているかどうかをテストします。

// Test whether guarantee is Stable.
if ((guarantee & ComponentGuaranteesOptions.Stable) == ComponentGuaranteesOptions.Stable)
   Console.WriteLine($"{typ.Name} is marked as {guarantee}.");
' Test whether guarantee is Stable.
If (guarantee And ComponentGuaranteesOptions.Stable) = ComponentGuaranteesOptions.Stable Then
   Console.WriteLine("{0} is marked as {1}.", typ.Name, guarantee)
End If

次の例では、型が Stable または Exchangeとしてマークされているかどうかをテストします。

// Test whether guarantee is Stable or Exchange.
if ((guarantee & (ComponentGuaranteesOptions.Stable | ComponentGuaranteesOptions.Exchange)) > 0)
   Console.WriteLine($"{typ.Name} is marked as Stable or Exchange.");
' Test whether guarantee is Stable or Exchange.
If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) > 0 Then
   Console.WriteLine("{0} is marked as Stable or Exchange.", typ.Name, guarantee)
End If

次の例では、型が None としてマークされているかどうかをテストします (つまり、 StableExchangeでもありません)。

// Test whether there is no guarantee (neither Stable nor Exchange).
if ((guarantee & (ComponentGuaranteesOptions.Stable | ComponentGuaranteesOptions.Exchange)) == 0)
   Console.WriteLine($"{typ.Name} has no compatibility guarantee.");
' Test whether there is no guarantee (neither Stable nor Exchange).
If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) = 0 Then
   Console.WriteLine("{0} has no compatibility guarantee.", typ.Name, guarantee)
End If