System.AppContext classe

Este artigo fornece observações complementares à documentação de referência para essa API.

A AppContext classe permite que os escritores de biblioteca forneçam um mecanismo de exclusão uniforme para novas funcionalidades para seus usuários. Ela estabelece um contrato flexível entre componentes a fim de comunicar uma solicitação de recusa. Normalmente, essa funcionalidade é importante quando uma alteração é feita na funcionalidade existente. Por outro lado, já existe uma aceitação implícita da nova funcionalidade.

AppContext para desenvolvedores de bibliotecas

As bibliotecas usam a AppContext classe para definir e expor opções de compatibilidade, enquanto os usuários da biblioteca podem definir essas opções para afetar o comportamento da biblioteca. Por padrão, as bibliotecas fornecem a nova funcionalidade, e apenas a alteram (ou seja, eles fornecem a funcionalidade anterior) se a opção for definida. Isso permite que as bibliotecas forneçam um novo comportamento para uma API existente enquanto continuam a oferecer suporte a chamadores que dependem do comportamento anterior.

Definir o nome do switch

A maneira mais comum de permitir que os consumidores de sua biblioteca optem por não participar de uma mudança de comportamento é definir um switch nomeado. Seu value elemento é um par nome/valor que consiste no nome de um switch e seu Boolean valor. Por padrão, a opção é sempre implicitamente false, o que fornece o novo comportamento (e torna o novo comportamento opt-in por padrão). Definir o switch para true habilitá-lo, o que fornece o comportamento herdado. Definir explicitamente a opção para false também fornece o novo comportamento.

É benéfico usar um formato consistente para alternar nomes, já que eles são um contrato formal exposto por uma biblioteca. A seguir estão dois formatos óbvios:

  • Opção.namespace.nomedaopção
  • Opção.biblioteca.nomedaopção

Depois de definir e documentar o switch, os chamadores podem usá-lo chamando o AppContext.SetSwitch(String, Boolean) método programaticamente. Os aplicativos do .NET Framework também podem usar a opção adicionando um <elemento AppContextSwitchOverrides ao arquivo de configuração do> aplicativo ou usando o Registro. Para obter mais informações sobre como os chamadores usam e definem o valor das opções de configuração, consulte a seção AppContext para consumidores de AppContext biblioteca.

No .NET Framework, quando o Common Language Runtime executa um aplicativo, ele lê automaticamente as configurações de compatibilidade do Registro e carrega o arquivo de configuração do aplicativo para preencher a instância do AppContext aplicativo. Como a instância é preenchida programaticamente pelo chamador ou pelo tempo de execução, os aplicativos do .NET Framework não precisam executar nenhuma ação, como chamar o SetSwitch método, para configurar a AppContextAppContext instância.

Verifique a configuração

Você pode verificar se um consumidor declarou o valor do switch e agir adequadamente chamando o AppContext.TryGetSwitch método. O método retorna true se o argumento for encontrado e seu isEnabled argumento indica o switchName valor da opção. Do contrário, o método retorna false.

Exemplo

O exemplo a seguir ilustra o uso da AppContext classe para permitir que o cliente escolha o comportamento original de um método de biblioteca. A seguir está a versão 1.0 de uma biblioteca chamada StringLibrary. Ele define um SubstringStartsAt método que executa uma comparação ordinal para determinar o índice inicial de uma subcadeia de caracteres dentro de uma cadeia de caracteres maior.

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

O exemplo a seguir usa a biblioteca para localizar o índice inicial da subcadeia de caracteres "archæ" em "O arqueólogo". Como o método executa uma comparação ordinal, a substring não pode ser encontrada.

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'

A versão 2.0 da biblioteca, no entanto, altera o método para usar a comparação sensível à SubstringStartsAt cultura.

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

Quando o aplicativo é recompilado para ser executado contra a nova versão da biblioteca, ele agora relata que a substring "archæ" é encontrada no índice 4 em "O arqueólogo".

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

Essa alteração pode ser impedida de quebrar os aplicativos que dependem do comportamento original definindo uma opção. Nesse caso, a opção é chamada StringLibrary.DoNotUseCultureSensitiveComparison. Seu valor padrão, , falseindica que a biblioteca deve executar sua comparação sensível à cultura da versão 2.0. true indica que a biblioteca deve executar sua comparação ordinal da versão 1.0. Uma pequena modificação do código anterior permite que o consumidor da biblioteca defina a opção para determinar o tipo de comparação que o método executa.

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

Um aplicativo .NET Framework pode usar o seguinte arquivo de configuração para restaurar o comportamento da versão 1.0.

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

Quando o aplicativo é executado com o arquivo de configuração presente, ele produz a seguinte saída:

'archæ' not found in 'The archaeologist'

AppContext para consumidores de bibliotecas

Se você for o consumidor de uma biblioteca, a AppContext classe permitirá que você aproveite o mecanismo de desativação de uma biblioteca ou método de biblioteca para novas funcionalidades. Os métodos individuais da biblioteca de classes que você está chamando definem opções específicas que habilitam ou desabilitam um novo comportamento. O valor do switch é booleano. Se for , que normalmente é o valor padrão, o novo comportamento será habilitado, se for falsetrue, o novo comportamento será desabilitado e o membro se comportará como antes.

Você pode definir o valor de uma opção chamando o AppContext.SetSwitch(String, Boolean) método em seu código. O switchName argumento define o nome da opção e a isEnabled propriedade define o valor da opção. Como AppContext é uma classe estática, ela está disponível por domínio de aplicativo. Chamar o tem escopo de aplicativo, ou seja, afeta apenas o AppContext.SetSwitch(String, Boolean) aplicativo.

Os aplicativos do .NET Framework têm maneiras adicionais de definir o valor de uma opção:

  • Adicionando um <AppContextSwitchOverrides> elemento à <seção de tempo de execução> do arquivo app.config. O switch tem um único atributo, value, cujo valor é uma cadeia de caracteres que representa um par chave/valor que contém o nome do switch e seu valor.

    Para definir várias opções, separe o <par chave/valor de cada switch no atributo do elemento AppContextSwitchOverrides>value com ponto-e-vírgula. Nesse caso, o elemento tem o <AppContextSwitchOverrides> seguinte formato:

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

    Usar o elemento para definir uma definição de configuração tem escopo de aplicativo, ou seja, afeta apenas o <AppContextSwitchOverrides> aplicativo.

    Observação

    Para obter informações sobre as opções definidas pelo .NET Framework, consulte <AppContextSwitchOverrides> elemento.

  • Adicionando uma entrada ao registro. Adicione um novo valor de cadeia de caracteres ao HKLM\SOFTWARE\Microsoft\. NETFramework\AppContext subchave. Defina o nome da entrada como o nome do switch. Defina seu valor como uma das seguintes opções: True, , trueFalseou false. Se o tempo de execução encontrar qualquer outro valor, ele ignorará a opção.

    Em um sistema operacional de 64 bits, você também deve adicionar a mesma entrada ao HKLM\SOFTWARE\Wow6432Node\Microsoft\. NETFramework\AppContext subchave.

    Usar o registro para definir um AppContext switch tem escopo de máquina, ou seja, afeta todos os aplicativos em execução na máquina.

Para aplicativos ASP.NET e ASP.NET Core, defina uma opção adicionando um <elemento Add> à <seção appSettings> do arquivo web.config. Por exemplo:

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

Se você definir a mesma opção de mais de uma maneira, a ordem de precedência para determinar qual configuração substitui as outras será:

  1. A configuração programática.
  2. A configuração no arquivo app.config (para aplicativos .NET Framework) ou no arquivo web.config (para aplicativos ASP.NET Core).
  3. A configuração do Registro (somente para aplicativos do .NET Framework).

Confira também