Classe System.AppContext

Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.

La AppContext classe consente ai writer di librerie di fornire un meccanismo di rifiuto esplicito uniforme per le nuove funzionalità per gli utenti. Stabilisce un contratto ad accoppiamento debole tra i componenti per comunicare una richiesta di rifiuto esplicito. Questa funzionalità è importante in genere quando viene apportata una modifica alle funzionalità esistenti. Al contrario, esiste già un consenso esplicito per la nuova funzionalità.

AppContext per sviluppatori di librerie

Le librerie usano la AppContext classe per definire ed esporre commutatori di compatibilità, mentre gli utenti della libreria possono impostare tali opzioni per influire sul comportamento della libreria. Per impostazione predefinita, le librerie forniscono la nuova funzionalità e la modificano (cioè offrono la funzionalità precedente) solo se l'opzione è impostata. Ciò consente alle librerie di fornire un nuovo comportamento per un'API esistente, continuando a supportare i chiamanti che dipendono dal comportamento precedente.

Definire il nome dell'opzione

Il modo più comune per consentire ai consumer della libreria di rifiutare esplicitamente una modifica del comportamento consiste nel definire un'opzione denominata. Il relativo value elemento è una coppia nome/valore costituita dal nome di un'opzione e dal relativo Boolean valore. Per impostazione predefinita, l'opzione è sempre implicitamente false, che fornisce il nuovo comportamento (e rende il nuovo comportamento consenso esplicito per impostazione predefinita). L'impostazione dell'opzione su true lo abilita, che fornisce il comportamento legacy. L'impostazione esplicita dell'opzione su false fornisce anche il nuovo comportamento.

È utile usare un formato coerente per i nomi dei cambi, perché sono un contratto formale esposto da una libreria. Di seguito sono riportati due formati ovvi:

  • Opzione.spaziodeinomi.nomeopzione
  • Opzione.libreria.nomeopzione

Dopo aver definito e documentare l'opzione, i chiamanti possono usarlo chiamando il AppContext.SetSwitch(String, Boolean) metodo a livello di codice. Le app .NET Framework possono anche usare l'opzione aggiungendo un <elemento AppContextSwitchOverrides> al file di configurazione dell'applicazione o usando il Registro di sistema. Per altre informazioni su come i chiamanti usano e impostano il valore delle opzioni di configurazione, vedere la sezione AppContext per i consumer di AppContext libreria.

In .NET Framework, quando Common Language Runtime esegue un'applicazione, legge automaticamente le impostazioni di compatibilità del Registro di sistema e carica il file di configurazione dell'applicazione per popolare l'istanza dell'applicazione AppContext . Poiché l'istanza AppContext viene popolata a livello di codice dal chiamante o dal runtime, le app .NET Framework non devono eseguire alcuna azione, ad esempio la chiamata al SetSwitch metodo, per configurare l'istanza AppContext .

Controllare l'impostazione

È possibile verificare se un consumer ha dichiarato il valore dell'opzione e agire in modo appropriato chiamando il AppContext.TryGetSwitch metodo . Il metodo restituisce true se l'argomento switchName viene trovato e il relativo isEnabled argomento indica il valore dell'opzione. In caso contrario, il metodo restituisce false.

Esempio

Nell'esempio seguente viene illustrato l'uso della AppContext classe per consentire al cliente di scegliere il comportamento originale di un metodo di libreria. Di seguito è riportata la versione 1.0 di una libreria denominata StringLibrary. Definisce un metodo che esegue un SubstringStartsAt confronto ordinale per determinare l'indice iniziale di una sottostringa all'interno di una stringa più grande.

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

L'esempio seguente usa quindi la libreria per trovare l'indice iniziale della sottostringa "archæ" in "The archeolog". Poiché il metodo esegue un confronto ordinale, non è possibile trovare la sottostringa.

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'

La versione 2.0 della libreria, tuttavia, modifica il metodo per usare un SubstringStartsAt confronto sensibile alle impostazioni 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 l'app viene ricompilata per essere eseguita sulla nuova versione della libreria, ora segnala che la sottostringa "archæ" si trova nell'indice 4 in "The archeolog".

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

Questa modifica può essere impedita di interrompere le applicazioni che dipendono dal comportamento originale definendo un commutatore. In questo caso, l'opzione è denominata StringLibrary.DoNotUseCultureSensitiveComparison. Il valore predefinito, false, indica che la libreria deve eseguire il confronto con le impostazioni cultura della versione 2.0. true indica che la libreria deve eseguire il confronto ordinale versione 1.0. Una leggera modifica del codice precedente consente al consumer della libreria di impostare l'opzione per determinare il tipo di confronto eseguito dal metodo.

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

Un'applicazione .NET Framework può quindi usare il file di configurazione seguente per ripristinare il comportamento della versione 1.0.

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

Quando l'applicazione viene eseguita con il file di configurazione presente, genera l'output seguente:

'archæ' not found in 'The archaeologist'

AppContext per i consumer di librerie

Se si è il consumer di una libreria, la AppContext classe consente di sfruttare il meccanismo di rifiuto esplicito di una libreria o di un metodo di libreria per le nuove funzionalità. I singoli metodi della libreria di classi che si stanno chiamando definiscono opzioni specifiche che abilitano o disabilitano un nuovo comportamento. Il valore dell'opzione è un valore booleano. Se è false, che è in genere il valore predefinito, il nuovo comportamento viene abilitato; se è true, il nuovo comportamento è disabilitato e il membro si comporta come in precedenza.

È possibile impostare il valore di un'opzione chiamando il AppContext.SetSwitch(String, Boolean) metodo nel codice. L'argomento switchName definisce il nome dell'opzione e la isEnabled proprietà definisce il valore dell'opzione. Poiché AppContext è una classe statica, è disponibile per ogni dominio applicazione. La chiamata a ha ambito AppContext.SetSwitch(String, Boolean) applicazione, ovvero influisce solo sull'applicazione.

Le app .NET Framework hanno modi aggiuntivi per impostare il valore di un'opzione:

  • Aggiungendo un <AppContextSwitchOverrides> elemento alla <sezione runtime> del file app.config. L'opzione ha un singolo attributo, value, il cui valore è una stringa che rappresenta una coppia chiave/valore contenente sia il nome dell'opzione che il relativo valore.

    Per definire più commutatori, separare la coppia chiave/valore di ogni opzione nell'attributo <dell'elemento value AppContextSwitchOverrides> con un punto e virgola. In tal caso, l'elemento <AppContextSwitchOverrides> ha il formato seguente:

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

    L'uso dell'elemento per definire un'impostazione <AppContextSwitchOverrides> di configurazione ha un ambito dell'applicazione, ovvero influisce solo sull'applicazione.

    Nota

    Per informazioni sulle opzioni definite da .NET Framework, vedere <Elemento AppContextSwitchOverrides>.

  • Aggiungendo una voce al Registro di sistema. Aggiungere un nuovo valore stringa a HKLM\SOFTWARE\Microsoft\. Sottochiave NETFramework\AppContext . Impostare il nome della voce sul nome dell'opzione. Impostare il relativo valore su una delle opzioni seguenti: True, true, Falseo false. Se il runtime rileva qualsiasi altro valore, ignora l'opzione.

    In un sistema operativo a 64 bit è necessario aggiungere anche la stessa voce a HKLM\SOFTWARE\Wow6432Node\Microsoft\. Sottochiave NETFramework\AppContext .

    L'uso del Registro di sistema per definire un AppContext commutatore ha un ambito computer, ovvero influisce su ogni applicazione in esecuzione nel computer.

Per le applicazioni ASP.NET e ASP.NET Core, è possibile impostare un'opzione aggiungendo un elemento Add> all'app <Impostazioni> sezione del file web.config.< Ad esempio:

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

Se si imposta lo stesso commutatore in più modi, l'ordine di precedenza per determinare quale impostazione sostituisce le altre è:

  1. Impostazione a livello di codice.
  2. L'impostazione nel file app.config (per le app .NET Framework) o nel file web.config (per le app ASP.NET Core).
  3. Impostazione del Registro di sistema (solo per le app .NET Framework).

Vedi anche