System.AppContext クラス

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

この AppContext クラスを使用すると、ライブラリ ライターは、ユーザーの新機能に対して統一されたオプトアウト メカニズムを提供できます。 これにより、オプトアウト要求を伝達するために、コンポーネント間に疎結合のコントラクトが確立されます。 通常、この機能は既存の機能が変更されるときに重要となります。 それに対して、新しい機能には暗黙のオプトインが既に存在しています。

ライブラリ開発者向けの AppContext

ライブラリはクラスを AppContext 使用して互換性スイッチを定義および公開しますが、ライブラリ ユーザーはこれらのスイッチを設定してライブラリの動作に影響を与えることができます。 ライブラリは、既定では新しい機能を提供し、スイッチが設定されている場合のみそれを変更する (つまり以前の機能を提供する) ことができます。 これにより、ライブラリは、以前の動作に依存する呼び出し元を引き続きサポートしながら、既存の API に新しい動作を提供できます。

スイッチ名を定義する

ライブラリのコンシューマーが動作の変更をオプトアウトできるようにする最も一般的な方法は、名前付きスイッチを定義することです。 その value 要素は、スイッチの名前とその Boolean 値で構成される名前と値のペアです。 既定では、スイッチは常に暗黙的に false行われ、新しい動作が提供されます (新しい動作は既定でオプトインされます)。 スイッチを有効に設定 true すると、従来の動作が提供されます。 スイッチを明示的に設定すると false 、新しい動作も提供されます。

スイッチ名はライブラリによって公開される正式なコントラクトであるため、一貫性のある形式を使用すると便利です。 2 つの明白な形式を次に示します。

  • Switch.namespace.switchname
  • Switch.library.switchname

スイッチを定義して文書化すると、呼び出し元はプログラムでメソッドを呼び出すことによってスイッチを AppContext.SetSwitch(String, Boolean) 使用できます。 .NET Framework アプリでは、AppContextSwitchOverrides> 要素を<アプリケーション構成ファイルに追加するか、レジストリを使用して、スイッチを使用することもできます。 呼び出し元が構成スイッチの値を使用して設定する方法のAppContext詳細については、「ライブラリ コンシューマーの AppContext」セクションを参照してください。

.NET Framework では、共通言語ランタイムがアプリケーションを実行すると、レジストリの互換性設定が自動的に読み取られ、アプリケーションのインスタンスが設定されるアプリケーション構成ファイルが AppContext 読み込まれます。 AppContextインスタンスは呼び出し元またはランタイムによってプログラムによって設定されるため、.NET Framework アプリは、インスタンスを構成AppContextするためにメソッドのSetSwitch呼び出しなどのアクションを実行する必要はありません。

設定を確認する

コンシューマーがスイッチの値を宣言し、メソッドを呼び出AppContext.TryGetSwitchして適切に動作するかどうかをチェックできます。 このメソッドは引数が見つかった場合にswitchNametrueり、そのisEnabled引数はスイッチの値を示します。 それ以外の場合、メソッドは false を返します。

次の例は、クラスを AppContext 使用して、お客様がライブラリ メソッドの元の動作を選択できるようにする方法を示しています。 次に示すのは、バージョン 1.0 という名前 StringLibraryのライブラリです。 より大きな文字列内の部分文字列の開始インデックスを決定するために序数比較を実行するメソッドを定義 SubstringStartsAt します。

using System;
using System.Reflection;

[assembly: AssemblyVersion("1.0.0.0")]

public static class StringLibrary1
{
    public static int SubstringStartsAt(string fullString, string substr)
    {
        return fullString.IndexOf(substr, StringComparison.Ordinal);
    }
}
open System
open System.Reflection

[<assembly: AssemblyVersion("1.0.0.0")>]
do ()

module StringLibrary =
    let substringStartsAt (fullString: string) (substr: string) =
        fullString.IndexOf(substr, StringComparison.Ordinal)
Imports System.Reflection

<Assembly: AssemblyVersion("1.0.0.0")>

Public Class StringLibrary
   Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
      Return fullString.IndexOf(substr, StringComparison.Ordinal)
   End Function
End Class

次の例では、ライブラリを使用して、"考古学者" の部分文字列 "archæ" の開始インデックスを見つけます。 メソッドは序数比較を実行するため、部分文字列が見つかりません。

using System;

public class Example1
{
    public static void Main()
    {
        string value = "The archaeologist";
        string substring = "archæ";
        int position = StringLibrary1.SubstringStartsAt(value, substring);
        if (position >= 0)
            Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
                           substring, value, position);
        else
            Console.WriteLine("'{0}' not found in '{1}'", substring, value);
    }
}
// The example displays the following output:
//       'archæ' not found in 'The archaeologist'
let value = "The archaeologist"
let substring = "archæ"

let position =
    StringLibrary.substringStartsAt value substring

if position >= 0 then
    printfn $"'{substring}' found in '{value}' starting at position {position}"
else
    printfn $"'{substring}' not found in '{value}'"

// The example displays the following output:
//       'archæ' not found in 'The archaeologist'
Public Module Example4
    Public Sub Main()
        Dim value As String = "The archaeologist"
        Dim substring As String = "archæ"
        Dim position As Integer = StringLibrary.SubstringStartsAt(value, substring)
        If position >= 0 Then
            Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
                        substring, value, position)
        Else
            Console.WriteLine("'{0}' not found in '{1}'", substring, value)
        End If
    End Sub
End Module
' The example displays the following output:
'       'archæ' not found in 'The archaeologist'

ただし、ライブラリのバージョン 2.0 では、カルチャに依存する比較を SubstringStartsAt 使用するようにメソッドが変更されます。

using System;
using System.Reflection;

[assembly: AssemblyVersion("2.0.0.0")]

public static class StringLibrary2
{
    public static int SubstringStartsAt(string fullString, string substr)
    {
        return fullString.IndexOf(substr, StringComparison.CurrentCulture);
    }
}
open System
open System.Reflection

[<assembly: AssemblyVersion("2.0.0.0")>]
do ()

module StringLibrary =
    let substringStartsAt (fullString: string) (substr: string) =
        fullString.IndexOf(substr, StringComparison.CurrentCulture)
Imports System.Reflection

<Assembly: AssemblyVersion("2.0.0.0")>

Public Class StringLibrary
   Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
      Return fullString.IndexOf(substr, StringComparison.CurrentCulture)
   End Function
End Class

新しいバージョンのライブラリに対して実行するようにアプリを再コンパイルすると、サブ文字列 "archæ" が "考古学者" のインデックス 4 にあることが報告されるようになりました。

using System;

public class Example2
{
    public static void Main()
    {
        string value = "The archaeologist";
        string substring = "archæ";
        int position = StringLibrary2.SubstringStartsAt(value, substring);
        if (position >= 0)
            Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
                           substring, value, position);
        else
            Console.WriteLine("'{0}' not found in '{1}'", substring, value);
    }
}
// The example displays the following output:
//       'archæ' found in 'The archaeologist' starting at position 4
let value = "The archaeologist"
let substring = "archæ"

let position =
    StringLibrary.substringStartsAt value substring

if position >= 0 then
    printfn $"'{substring}' found in '{value}' starting at position {position}"
else
    printfn $"'{substring}' not found in '{value}'"

// The example displays the following output:
//       'archæ' found in 'The archaeologist' starting at position 4
Public Module Example6
    Public Sub Main()
        Dim value As String = "The archaeologist"
        Dim substring As String = "archæ"
        Dim position As Integer = StringLibrary.SubstringStartsAt(value, substring)
        If position >= 0 Then
            Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
                        substring, value, position)
        Else
            Console.WriteLine("'{0}' not found in '{1}'", substring, value)
        End If
    End Sub
End Module
' The example displays the following output:
'       'archæ' found in 'The archaeologist' starting at position 4

この変更は、スイッチを定義することで、元の動作に依存するアプリケーションを中断しないようにすることができます。 この場合、スイッチに名前が付けられます StringLibrary.DoNotUseCultureSensitiveComparison。 既定値は、 falseライブラリがバージョン 2.0 のカルチャに依存する比較を実行する必要があることを示します。 true は、ライブラリがバージョン 1.0 の序数比較を実行する必要があることを示します。 前のコードを少し変更すると、ライブラリ コンシューマーはスイッチを設定して、メソッドが実行する比較の種類を決定できます。

using System;
using System.Reflection;

[assembly: AssemblyVersion("2.0.0.0")]

public static class StringLibrary
{
   public static int SubstringStartsAt(string fullString, string substr)
   {
      bool flag;
      if (AppContext.TryGetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison", out flag) && flag == true)
         return fullString.IndexOf(substr, StringComparison.Ordinal);
      else
         return fullString.IndexOf(substr, StringComparison.CurrentCulture);
   }
}
open System
open System.Reflection

[<assembly: AssemblyVersion("2.0.0.0")>]
do ()

AppContext.SetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison",true)

module StringLibrary =
    let substringStartsAt (fullString: string) (substr: string) =
        match AppContext.TryGetSwitch "StringLibrary.DoNotUseCultureSensitiveComparison" with 
        | true, true -> fullString.IndexOf(substr, StringComparison.Ordinal)
        | _ -> fullString.IndexOf(substr, StringComparison.CurrentCulture)
Imports System.Reflection

<Assembly: AssemblyVersion("2.0.0.0")>

Public Class StringLibrary
   Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
      Dim flag As Boolean
      If AppContext.TryGetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison", flag) AndAlso flag = True Then
         Return fullString.IndexOf(substr, StringComparison.Ordinal)
      Else
         Return fullString.IndexOf(substr, StringComparison.CurrentCulture)
      End If   
   End Function
End Class

.NET Framework アプリケーションでは、次の構成ファイルを使用してバージョン 1.0 の動作を復元できます。

<configuration>
   <runtime>
      <AppContextSwitchOverrides value="StringLibrary.DoNotUseCultureSensitiveComparison=true" />
   </runtime>
</configuration>

構成ファイルが存在するアプリケーションを実行すると、次の出力が生成されます。

'archæ' not found in 'The archaeologist'

ライブラリ コンシューマー向けの AppContext

ライブラリのコンシューマーである場合、このクラスを使用すると、 AppContext ライブラリまたはライブラリ メソッドのオプトアウト メカニズムを利用して新しい機能を利用できます。 呼び出すクラス ライブラリの個々のメソッドは、新しい動作を有効または無効にする特定のスイッチを定義します。 スイッチの値はブール値です。 既定値である場合は false、新しい動作が有効になります。有効な場合は true、新しい動作が無効になり、メンバーは以前と同じように動作します。

コードでメソッドを呼び出すことで、スイッチの値を AppContext.SetSwitch(String, Boolean) 設定できます。 引数は switchName スイッチ名を定義し、プロパティは isEnabled スイッチの値を定義します。 静的クラスであるためAppContext、アプリケーションごとにメイン使用できます。 呼び出し元は AppContext.SetSwitch(String, Boolean) アプリケーション スコープを持ちます。つまり、アプリケーションにのみ影響します。

.NET Framework アプリには、スイッチの値を設定する追加の方法があります。

  • app.config ファイルの<ランタイム> セクションに要素を追加<AppContextSwitchOverrides>する。 スイッチには 1 つの属性があり、 valueその値は、スイッチ名とその値の両方を含むキーと値のペアを表す文字列です。

    複数のスイッチを定義するには、AppContextSwitchOverrides 要素の属性で<各スイッチのキーと値のvalueペアをセミコロンで区切ります。> その場合、要素の <AppContextSwitchOverrides> 形式は次のとおりです。

    <AppContextSwitchOverrides value="switchName1=value1;switchName2=value2" />
    

    要素を <AppContextSwitchOverrides> 使用して構成設定を定義すると、アプリケーション スコープが与えられます。つまり、アプリケーションにのみ影響します。

    Note

    .NET Framework で定義されているスイッチの詳細については、「AppContextSwitchOverrides 要素」を参照してください<。>

  • レジストリにエントリを追加する。 HKLM\SOFTWARE\Microsoft\ に 新しい文字列値を追加します。NETFramework\AppContext サブキー。 エントリの名前をスイッチの名前に設定します。 値を次のいずれかのオプションに設定します。 TruetrueFalsefalse ランタイムが他の値を検出すると、スイッチは無視されます。

    64 ビット オペレーティング システムでは、HKLM\SOFTWARE\Wow6432Node\Microsoft\ にも 同じエントリを追加する必要があります。NETFramework\AppContext サブキー。

    レジストリを使用してスイッチを AppContext 定義すると、マシン スコープが設定されます。つまり、マシン上で実行されているすべてのアプリケーションに影響します。

ASP.NET および ASP.NET Core アプリケーションの場合は、web.config ファイルの app設定> セクションに< Add> 要素を追加<してスイッチを設定します。 次に例を示します。

<appSettings>
   <add key="AppContext.SetSwitch:switchName1" value="switchValue1" />
   <add key="AppContext.SetSwitch:switchName2" value="switchValue2" />
</appSettings>

同じスイッチを複数の方法で設定した場合、他の設定をオーバーライドする設定を決定する優先順位は次のようになります。

  1. プログラムによる設定。
  2. app.config ファイル (.NET Framework アプリの場合) または web.config ファイル (ASP.NET Core アプリの場合) の設定。
  3. レジストリ設定 (.NET Framework アプリの場合のみ)。

関連項目