AppContext 类

定义

提供用于设置和检索应用程序上下文相关数据的成员。Provides members for setting and retrieving data about an application's context.

public ref class AppContext abstract sealed
public static class AppContext
type AppContext = class
Public Class AppContext
继承
AppContext

注解

AppContext类使库编写器可为其用户提供新功能的统一退出机制。The AppContext class enables library writers to provide a uniform opt-out mechanism for new functionality for their users. 它在组件之间建立松耦合的协定,以便与选择退出请求进行通信。It establishes a loosely-coupled contract between components in order to communicate an opt-out request. 对现有功能进行更改时,此功能通常很重要。This capability is typically important when a change is made to existing functionality. 相反,已有新功能隐式选择加入。Conversely, there is already an implicit opt-in for new functionality.

适用于库开发人员的 AppContextAppContext for library developers

库使用AppContext类来定义和公开兼容性开关,而库用户可以设置这些开关以影响库行为。Libraries use the AppContext class to define and expose compatibility switches, while library users can set those switches to affect the library behavior. 默认情况下,库提供新功能;如果设置了开关,则只更改新功能(即,它们提供以前的功能)。By default, libraries provide the new functionality, and they only alter it (that is, they provide the previous functionality) if the switch is set. 这允许库为现有 API 提供新行为,同时继续支持依赖于先前行为的调用方。This allows libraries to provide new behavior for an existing API while continuing to support callers who depend on the previous behavior.

定义开关名称Defining the switch name

若要允许库的使用者选择不更改行为,最常见的方法是定义命名开关。The most common way to allow consumers of your library to opt out of a change of behavior is to define a named switch. value元素是一个名称/值对,它包含开关的名称Boolean及其值。Its value element is a name/value pair that consists of the name of a switch and its Boolean value. 默认情况下,开关始终是隐false式的,这将提供新的行为(并在默认情况下使新行为可选)。By default, the switch is always implicitly false, which provides the new behavior (and makes the new behavior opt-in by default). 通过设置开关来true启用它,它提供了旧行为。Setting the switch to true enables it, which provides the legacy behavior. 将开关显式设置为false也可提供新的行为。Explicitly setting the switch to false also provides the new behavior.

使用一致的开关名称格式是有益的,因为它们是由库公开的正式协定。It's beneficial to use a consistent format for switch names, since they are a formal contract exposed by a library. 以下是两种明显的格式。The following are two obvious formats.

  • Switch.namespace.switchnameSwitch.namespace.switchname

  • Switch.library.switchnameSwitch.library.switchname

定义并记录开关后,调用方可以使用注册表、将 <AppContextSwitchOverrides >元素添加到其应用程序配置文件中AppContext.SetSwitch(String, Boolean)或以编程方式调用方法来使用该开关。Once you define and document the switch, callers can use it by using the registry, by adding an <AppContextSwitchOverrides> element to their application configuration file, or by calling the AppContext.SetSwitch(String, Boolean) method programmatically. 有关调用方如何使用和设置配置开关值的AppContext详细信息,请参阅AppContext for library 使用者部分。See the AppContext for library consumers section for more information about how callers use and set the value of AppContext configuration switches.

当公共语言运行时运行应用程序时,它会自动读取注册表的兼容性设置并加载应用程序配置文件,以便填充应用程序AppContext的实例。When the common language runtime runs an application, it automatically reads the registry's compatibility settings and loads the application configuration file in order to populate the application's AppContext instance. 由于实例AppContext是由调用方或运行时以编程方式填充的,因此您无需执行任何操作(如SetSwitch调用AppContext方法)来配置实例。Because the AppContext instance is populated either programmatically by the caller or by the runtime, you do not have to take any action, such as calling the SetSwitch method, to configure the AppContext instance.

检查设置Checking the setting

然后,可以通过调用AppContext.TryGetSwitch方法来检查使用者是否声明了开关的值并进行了相应的操作。You can then check if a consumer has declared the value of the switch and act appropriately by calling the AppContext.TryGetSwitch method. 如果找到了true switchName参数,则该方法返回; 当方法返回时,它isEnabled的参数指示开关的值。The method returns true if the switchName argument is found, and when the method returns, its isEnabled argument indicates the value of the switch. 否则,该方法将返回 falseOtherwise, the method returns false.

示例An example

下面的示例演示如何使用AppContext类,以允许客户选择库方法的原始行为。The following example illustrates the use of the AppContext class to allow the customer to choose the original behavior of a library method. 下面是名为StringLibrary的库的版本1.0。The following is version 1.0 of a library named StringLibrary. 它定义了SubstringStartsAt一种方法,该方法执行序号比较,以确定较大字符串中子字符串的起始索引。It defines a SubstringStartsAt method that performs an ordinal comparison to determine the starting index of a substring within a larger string.

using System;
using System.Reflection;

[assembly: AssemblyVersion("1.0.0.0")]

public static class StringLibrary
{
   public static int SubstringStartsAt(String fullString, String substr)
   {
      return 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

然后,下面的示例使用库在 "archaeologist" 中查找子字符串 "archæ" 的起始索引。The following example then uses the library to find the starting index of the substring "archæ" in "The archaeologist". 由于方法执行序号比较,因此无法找到子字符串。Because the method performs an ordinal comparison, the substring cannot be found.

using System;

public class Example
{
   public static void Main()
   {
      String value = "The archaeologist";
      String substring = "archæ";
      int position = StringLibrary.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'
Public Module Example
   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将SubstringStartsAt方法更改为使用区分区域性的比较。Version 2 of the library, however, changes the SubstringStartsAt method to use culture-sensitive comparison.

using System;
using System.Reflection;

[assembly: AssemblyVersion("2.0.0.0")]

public static class StringLibrary
{
   public static int SubstringStartsAt(String fullString, String substr)
   {
      return 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

当重新编译应用程序以针对新版本的库运行时,它现在会报告在 "archaeologist" 的索引4找到了子字符串 "archæ"。When the app is recompiled to run against the new version of the library, it now reports that the substring "archæ" is found at index 4 in "The archaeologist".

using System;

public class Example
{
   public static void Main()
   {
      String value = "The archaeologist";
      String substring = "archæ";
      int position = StringLibrary.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   
Public Module Example
   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

通过定义 <AppContextSwitchOverrides >开关,可以防止此更改中断依赖于原始行为的应用程序。This change can be prevented from breaking the applications that depend on the original behavior by defining an <AppContextSwitchOverrides> switch. 在这种情况下,开关的StringLibrary.DoNotUseCultureSensitiveComparison名称为。In this case, the switch is named StringLibrary.DoNotUseCultureSensitiveComparison. 默认值false为,指示库应执行其版本2.0 区分区域性的比较。Its default value, false, indicates that the library should perform its version 2.0 culture-sensitive comparison. true指示库应执行其版本1.0 的序号比较。true indicates that the library should perform its version 1.0 ordinal comparison. 对前面的代码进行少许修改后,库使用者可以设置开关来确定该方法所执行的比较类型。A slight modification of the previous code allows the library consumer to set the switch to determine the kind of comparison the method performs.

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);
         
   }
}
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

如果应用程序随后可以使用以下配置文件来还原版本1.0 的行为。If application can then use the following configuration file to restore the version 1.0 behavior.


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

当应用程序运行时,如果配置文件存在,它将生成以下输出:When the application is run with the configuration file present, it produces the following output:

'archæ' not found in 'The archaeologist'

适用于库使用者的 AppContextAppContext for library consumers

如果你是库的使用者, AppContext则可以使用类来利用适用于新功能的库或库方法的选择退出机制。If you are the consumer of a library, the AppContext class allows you to take advantage of a library or library method's opt-out mechanism for new functionality. 你要调用的类库的各个方法会定义启用或禁用新行为的特定开关。Individual methods of the class library that you are calling define particular switches that enable or disable a new behavior. 开关的值为布尔值。The value of the switch is a Boolean. 如果为false(通常为默认值),则启用新行为; 如果为true,则禁用新行为,并使成员的行为与以前相同。If it is false, which is typically the default value, the new behavior is enabled; if it is true, the new behavior is disabled, and the member behaves as it did previously.

可以通过以下四种方式之一设置开关的值:You can set the value of a switch in one of four ways:

  • 通过在代码AppContext.SetSwitch(String, Boolean)中调用方法。By calling the AppContext.SetSwitch(String, Boolean) method in your code. 参数定义开关名称, isEnabled属性定义开关的值。 switchNameThe switchName argument defines the switch name, and the isEnabled property defines the value of the switch. 由于AppContext是静态类,因此它在每个应用程序域的基础上可用。Because AppContext is a static class, it is available on a per-application domain basis.

    AppContext.SetSwitch(String, Boolean)调用具有应用程序作用域; 即,它只会影响应用程序。Calling the AppContext.SetSwitch(String, Boolean) has application scope; that is, it affects only the application.

  • 通过将<AppContextSwitchOverrides>元素添加到 app.config 文件的 <运行时 >部分。By adding an <AppContextSwitchOverrides> element to the <runtime> section of your app.config file. 开关只有一个属性, value它的值是一个字符串,表示同时包含开关名称和值的键/值对。The switch has a single attribute, value, whose value is a string that represents a key/value pair containing both the switch name and its value.

    若要定义多个开关,请将value <> AppContextSwitchOverrides中的每个开关的键/值对用分号隔开。To define multiple switches, separate each switch's key/value pair in the <AppContextSwitchOverrides> element's value attribute with a semicolon. 在这种情况下<AppContextSwitchOverrides> ,元素具有以下格式:In that case, the <AppContextSwitchOverrides> element has the following format:

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

    <AppContextSwitchOverrides>使用元素定义配置设置具有应用程序作用域; 即,它只会影响应用程序。Using the <AppContextSwitchOverrides> element to define a configuration setting has application scope; that is, it affects only the application.

    备注

    有关 .NET Framework 定义的开关的详细信息,请参阅 <AppContextSwitchOverrides > 元素For information on the switches defined by the .NET Framework, see the <AppContextSwitchOverrides> element.

  • 添加一个 string 值,其 name 为注册表中的HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext键的开关的名称。By adding a string value whose name is the name of the switch to the HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext key in the registry. 它的值必须是可以Boolean Boolean.Parse通过方法分析的的字符串表示形式; 也就是说,它必须是 "true"、"true"、"false" 或 "false"。Its value must be the string representation of a Boolean that can be parsed by the Boolean.Parse method; that is, it must be "True", "true", "False", or "false". 如果运行时遇到任何其他值,将忽略开关。If the runtime encounters any other value, it ignores the switch.

    使用注册表定义AppContext交换机具有计算机作用域; 即,它会影响计算机上运行的每个应用程序。Using the registry to define an AppContext switch has machine scope; that is, it affects every application running on the machine.

  • 对于 ASP.NET 应用程序,请将 <add >元素添加到 web.config 文件的 <appSettings >部分。For ASP.NET applications, you add an <Add> element to the <appSettings> section of the web.config file. 例如:For example:

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

如果你以多种方式设置相同的开关,则确定哪些设置将覆盖其他设置的优先顺序如下:If you set the same switch in more than one way, the order of precedence for determining which setting overrides the others is:

  1. 编程设置。The programmatic setting.

  2. 应用程序配置文件或 web.config 文件中的设置。The setting in the app config file or the web.config file.

  3. 注册表设置。The registry setting.

下面是一个将文件 URI 传递给Path.GetDirectoryName方法的简单应用程序。The following is a simple application that passes a file URI to the Path.GetDirectoryName method. 在 .NET Framework 4.6 下运行时,它将引发ArgumentExceptionfile://因为不再是文件路径的有效部分。When run under the .NET Framework 4.6, it throws an ArgumentException because file:// is no longer a valid part of a file path.

using System;
using System.IO;
using System.Runtime.Versioning;

[assembly:TargetFramework(".NETFramework,Version=v4.6.2")]

public class Example
{
   public static void Main()
   {
      Console.WriteLine(Path.GetDirectoryName("file://c/temp/dirlist.txt")); 
   }
}
// The example displays the following output:
//    Unhandled Exception: System.ArgumentException: The path is not of a legal form.
//       at System.IO.Path.NewNormalizePathLimitedChecks(String path, Int32 maxPathLength, Boolean expandShortPaths)
//       at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
//       at System.IO.Path.InternalGetDirectoryName(String path)
//       at Example.Main()
Imports System.IO
Imports System.Runtime.Versioning

<assembly:TargetFramework(".NETFramework,Version=v4.6.2")>

Module Example
   Public Sub Main()
      Console.WriteLine(Path.GetDirectoryName("file://c/temp/dirlist.txt")) 
   End Sub
End Module
' The example displays the following output:
'    Unhandled Exception: System.ArgumentException: The path is not of a legal form.
'       at System.IO.Path.NewNormalizePathLimitedChecks(String path, Int32 maxPathLength, Boolean expandShortPaths)
'       at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
'       at System.IO.Path.InternalGetDirectoryName(String path)
'       at Example.Main()

若要还原方法的以前行为并防止出现异常,可以将该Switch.System.IO.UseLegacyPathHandling开关添加到该示例的应用程序配置文件中:To restore the method's previous behavior and prevent the exception, you can add the Switch.System.IO.UseLegacyPathHandling switch to the application configuration file for the example:

<configuration>
    <runtime>
        <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=true" />
    </runtime>
</configuration>

请参阅See also

AppContext 开关AppContext switch

属性

BaseDirectory

获取程序集解析程序用于探测程序集的基目录的路径名。Gets the pathname of the base directory that the assembly resolver uses to probe for assemblies.

TargetFrameworkName

获取当前应用程序所针对的框架版本的名称。Gets the name of the framework version targeted by the current application.

方法

GetData(String)

返回分配给当前应用程序域的已命名数据元素的值。Returns the value of the named data element assigned to the current application domain.

SetSwitch(String, Boolean)

设置开关的值。Sets the value of a switch.

TryGetSwitch(String, Boolean)

尝试获取开关的值。Tries to get the value of a switch.

适用于

另请参阅