共用方式為


System.AppContext 類別

本文提供此 API 參考文件的補充備註。

AppContext 類別可讓程式庫開發者為其使用者提供統一的退出機制。 它會建立元件之間的鬆散結合合約,以傳達退出要求。 當對現有功能進行變更時,這項功能通常很重要。 相反地,對於新功能來說,已經有隱含的默認同意。

為程式庫開發人員提供的 AppContext

連結庫會使用 AppContext 類別來定義和公開相容性參數,而連結庫用戶可以設定這些參數來影響連結庫行為。 根據預設,程式庫會提供新功能,只有在設定開關時,它們才會改變功能(也就是說,它們會提供先前的功能)。 這可讓連結庫為現有的 API 提供新的行為,同時繼續支援相依於先前行為的呼叫端。

定義開關名稱

允許使用者選擇不改變行為的最常見方式是定義具名開關。 其 value 元素是由開關名稱及其 Boolean 值所組成的名稱/值對。 預設情況下,開關總是隱含設為 false,這將提供新的行為(並且預設情況下新行為會自動啟用)。 將開關設定為 true 會啟用它,從而提供舊版行為。 明確將開關設定為 false 也會提供新的行為。

使用一個一致的開關名稱格式是有益的,因為這些名稱是由程式庫公開的正式合約。 以下是兩種明顯的格式:

  • 開關命名空間switchname
  • 開關函式庫switchname

一旦您定義並記錄開關,呼叫端就可以透過程序設計方式呼叫 AppContext.SetSwitch(String, Boolean) 方法來使用它。 .NET Framework 應用程式也可以藉由將 <AppContextSwitchOverrides> 元素新增至其應用程式組態檔,或是使用登錄,來使用開關。 如需有關呼叫端如何使用及設定 AppContext 組態開關值的詳細資訊,請參閱針對程式庫使用者的AppContext 一節。

在 .NET Framework 中,當 Common Language Runtime 執行應用程式時,它會自動讀取登錄的相容性設定,並載入應用程式組態檔,以填入應用程式的 AppContext 實例。 由於 AppContext 實例是由呼叫端或運行時間以程式設計方式填入,因此 .NET Framework 應用程式不需要採取任何動作,例如呼叫 SetSwitch 方法,以設定 AppContext 實例。

檢查設定

您可以藉由呼叫 AppContext.TryGetSwitch 方法,檢查消費者是否已宣告開關的值,並據此採取適當的行動。 如果找到 switchName 參數,且其 isEnabled 參數顯示開關的值,則方法會傳回 true。 否則,方法會傳回 false

範例

下列範例說明如何使用 AppContext 類別,讓客戶選擇連結庫方法的原始行為。 以下是名為 StringLibrary的程式庫 1.0 版。 它會定義執行序數比較的 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

下列範例接著會使用函式庫來尋找「The archaeologist」中子字串「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($"'{substring}' found in '{value}' starting at position {position}");
        else
            Console.WriteLine($"'{substring}' not found in '{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

當應用程式重新編譯以針對新版程式庫執行時,現在會報告在「The archaeologist」的索引4中找到了子字串「archæ」。

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($"'{substring}' found in '{value}' starting at position {position}");
        else
            Console.WriteLine($"'{substring}' not found in '{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 應用程式有額外的方法來設定開關的值:

  • <AppContextSwitchOverrides> 元件新增至 app.config 檔案的 <執行時> 區段。 開關具有單一屬性,value,其值為字串,表示包含開關名稱和其值的鍵/值組。

    若要定義多個參數,請在appContextSwitchOverrides <AppContextSwitchOverrides 中分隔每個參數的索引鍵/值組,> 元素的 value 屬性加上分號。 在此情況下,<AppContextSwitchOverrides> 元素的格式如下:

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

    使用 <AppContextSwitchOverrides> 元素來定義組態設定具有應用程式範圍;也就是說,它只會影響應用程式。

    備註

    如需 .NET Framework 所定義之參數的資訊,請參閱 <AppContextSwitchOverrides> 元素

  • 將一個項目新增至登錄。 將新的字串值新增至 HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext 子機碼。 將項目的名稱設定為開關的名稱。 將設定為下列其中一個選項:TruetrueFalsefalse。 如果執行階段遇到任何其他值,則會忽略該切換。

    在 64 位作業系統上,您也必須將相同的項目新增至 HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AppContext 子機碼。

    使用登錄來定義 AppContext 開關具有電腦範圍;也就是說,它會影響電腦上執行的每個應用程式。

針對 ASP.NET 和 ASP.NET Core 應用程式,您可以在 web.config 檔案的 <appSettings> 區段中新增 <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 應用程式)。

另請參閱