本文提供此 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 方法,檢查消費者是否已宣告開關的值,並據此採取適當的行動。 如果找到 true 參數,且其 switchName 參數顯示開關的值,則方法會傳回 isEnabled。 否則,方法會傳回 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 檔案的<runtime>區段。 開關具有單一屬性,value,其值為字串,表示包含開關名稱和其值的鍵/值組。要定義多個開關,請用分號將每個開關的鍵值對分隔在元素
<AppContextSwitchOverrides>屬性value中。 在此情況下,<AppContextSwitchOverrides>元素的格式如下:<AppContextSwitchOverrides value="switchName1=value1;switchName2=value2" />使用
<AppContextSwitchOverrides>元素來定義組態設定具有應用程式範圍;也就是說,它只會影響應用程式。備註
關於 .NET Framework 定義的交換器資訊,請參見
<AppContextSwitchOverrides>元素。將一個項目新增至登錄。 將新的字串值新增至 HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext 子機碼。 將項目的名稱設定為開關的名稱。 將設定為下列其中一個選項:
True、true、False或false。 如果執行階段遇到任何其他值,則會忽略該切換。在 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>
如果您以一種以上的方式設定相同的開關,判斷哪些設定會覆蓋其他設定的優先順序為:
- 程式化設定。
- app.config 檔案中的設定(適用於 .NET Framework 應用程式)或 web.config 檔案(適用於 ASP.NET Core 應用程式)。
- 登錄設定 (僅適用於 .NET Framework 應用程式)。