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 子機碼。 將項目的名稱設定為開關的名稱。 將設定為下列其中一個選項:
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 應用程式)。