AppContext Klasse

Definition

Stellt Member zum Festlegen und Abrufen von Daten für einen Anwendungskontext bereit.

public ref class AppContext abstract sealed
public static class AppContext
type AppContext = class
Public Class AppContext
Vererbung
AppContext

Hinweise

Mit der AppContext Klasse können Bibliotheksautoren einen einheitlichen Opt-Out-Mechanismus für neue Funktionen für ihre Benutzer bereitstellen. Es richtet einen lose gekoppelten Vertrag zwischen den Komponenten ein, um eine Anforderung zur Abwahl zu übermitteln. Diese Möglichkeit ist in der Regel wichtig, wenn vorhandene Funktionalitäten verändert werden. Im Gegensatz dazu existiert bereits eine implizite Auswahloption für neue Funktionalitäten.

AppContext für Bibliotheksentwickler

Bibliotheken verwenden die AppContext Klasse, um Kompatibilitätsschalter zu definieren und verfügbar zu machen, während Bibliotheksbenutzer diese Schalter festlegen können, um das Bibliotheksverhalten zu beeinflussen. Standardmäßig stellen Bibliotheken die neue Funktionalität bereit. Nur wenn die Option festgelegt ist, stellen sie die vorherige Funktionalität bereit. Dadurch können Bibliotheken ein neues Verhalten für eine vorhandene API bereitstellen und gleichzeitig Anrufer unterstützen, die von dem vorherigen Verhalten abhängen.

Definieren des Switchnamens

Die am häufigsten verwendete Möglichkeit, den Verbrauchern Ihrer Bibliothek das Deaktivieren einer Verhaltensänderung zu ermöglichen, besteht darin, einen benannten Switch zu definieren. Das value Element ist ein Name/Wert-Paar, das aus dem Namen eines Schalters und dessen Boolean Wert besteht. Standardmäßig ist der Schalter immer implizit false, was das neue Verhalten bereitstellt (und das neue Verhalten standardmäßig aktiviert). Wenn Sie den Schalter true so festlegen, dass er aktiviert wird, wodurch das Legacyverhalten bereitgestellt wird. Durch explizites Festlegen des Schalters false wird auch das neue Verhalten bereitgestellt.

Es ist vorteilhaft, ein einheitliches Format für Switchnamen zu verwenden, da sie ein formaler Vertrag sind, der von einer Bibliothek verfügbar gemacht wird. Es folgen zwei offensichtliche Formate:

  • Switch.namespace.switchname

  • Switch.library.switchname

Nachdem Sie den Schalter definiert und dokumentiert haben, können Aufrufer sie verwenden, indem Sie die AppContext.SetSwitch(String, Boolean) Methode programmgesteuert aufrufen. .NET Framework Apps können auch den Schalter verwenden, indem sie ihrer Anwendungskonfigurationsdatei ein <AppContextSwitchOverrides> Element hinzufügen oder die Registrierung verwenden. Weitere Informationen zur Verwendung und Festlegung des Werts von AppContext Konfigurationsschaltern finden Sie im Abschnitt "AppContext für Bibliothekskunden ".

Wenn die .NET Framework allgemeine Sprachlaufzeit eine Anwendung ausführt, liest sie automatisch die Kompatibilitätseinstellungen der Registrierung und lädt die Anwendungskonfigurationsdatei, um die Instanz der Anwendung AppContext aufzufüllen. Da die AppContext Instanz programmgesteuert vom Aufrufer oder von der .NET Framework Laufzeit aufgefüllt wird, müssen .NET Framework Apps keine Aktion ausführen, z. B. das Aufrufen der SetSwitch Methode, um die AppContext Instanz zu konfigurieren.

Aktivieren Sie die Einstellung .

Sie können überprüfen, ob ein Verbraucher den Wert des Schalters deklariert hat und entsprechend handeln kann, indem Sie die AppContext.TryGetSwitch Methode aufrufen. Die Methode gibt zurück true , wenn das switchName Argument gefunden wird, und wenn die Methode zurückgegeben wird, gibt das isEnabled Argument den Wert des Schalters an. Andernfalls gibt diese Methode false zurück.

Beispiel

Im folgenden Beispiel wird die Verwendung der AppContext Klasse veranschaulicht, damit der Kunde das ursprüngliche Verhalten einer Bibliotheksmethode auswählen kann. Nachfolgend ist Version 1.0 einer Bibliothek mit dem Namen " StringLibrary. Es definiert eine Methode, die einen SubstringStartsAt Ordinalvergleich ausführt, um den Anfangsindex einer Teilzeichenfolge innerhalb einer größeren Zeichenfolge zu bestimmen.

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

Im folgenden Beispiel wird dann die Bibliothek verwendet, um den Anfangsindex der Teilzeichenfolge "archæ" in "The archæ" in "The archæist" zu finden. Da die Methode einen Ordinalvergleich ausführt, kann die Teilzeichenfolge nicht gefunden werden.

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'
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 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'

Version 2.0 der Bibliothek ändert jedoch die SubstringStartsAt Methode, um den kulturempfindlichen Vergleich zu verwenden.

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

Wenn die App neu kompiliert wird, um die neue Version der Bibliothek auszuführen, meldet sie nun, dass die Teilzeichenfolge "archæ" in Index 4 in "The archæist" gefunden wird.

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
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 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

Diese Änderung kann daran gehindert werden, die Anwendungen zu unterbrechen, die vom ursprünglichen Verhalten abhängen, indem sie einen Schalter definieren. In diesem Fall wird der Schalter benannt StringLibrary.DoNotUseCultureSensitiveComparison. Der Standardwert weist darauf hin, falsedass die Bibliothek den 2.0-Kultur-vertraulichen Vergleich durchführen soll. true gibt an, dass die Bibliothek den Vergleich der Version 1.0 durchführen soll. Eine geringfügige Änderung des vorherigen Codes ermöglicht es dem Bibliotheksanwender, den Schalter festzulegen, um die Art des Vergleichs zu bestimmen, den die Methode ausführt.

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

Eine .NET Framework Anwendung kann dann die folgende Konfigurationsdatei verwenden, um das Verhalten der Version 1.0 wiederherzustellen.

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

Wenn die Anwendung mit der vorhandenen Konfigurationsdatei ausgeführt wird, wird die folgende Ausgabe erzeugt:

'archæ' not found in 'The archaeologist'

AppContext für Bibliothekskunden

Wenn Sie der Verbraucher einer Bibliothek sind, kann die AppContext Klasse den Opt-Out-Mechanismus einer Bibliothek oder Bibliotheksmethode für neue Funktionen nutzen. Einzelne Methoden der Klassenbibliothek, die Sie aufrufen, definieren bestimmte Schalter, die ein neues Verhalten aktivieren oder deaktivieren. Der Wert des Schalters ist ein boolescher Wert. Wenn dies falseder Standardwert ist, wird das neue Verhalten aktiviert. Wenn es truesich um das neue Verhalten handelt, wird das neue Verhalten deaktiviert, und das Element verhält sich wie zuvor.

Sie können den Wert eines Schalters festlegen, indem Sie die AppContext.SetSwitch(String, Boolean) Methode in Ihrem Code aufrufen. Das switchName Argument definiert den Switchnamen, und die isEnabled Eigenschaft definiert den Wert des Schalters. Da AppContext es sich um eine statische Klasse handelt, ist sie auf Anwendungsdomänenbasis verfügbar. Das Aufrufen des AppContext.SetSwitch(String, Boolean) Anwendungsbereichs hat, also nur die Anwendung.

.NET Framework Apps haben zusätzliche Möglichkeiten zum Festlegen des Werts eines Schalters:

  • Durch Hinzufügen eines <AppContextSwitchOverrides> Elements zum <runtime> Abschnitt der app.config Datei. Der Schalter verfügt über ein einzelnes Attribut, dessen Wert eine Zeichenfolge ist, die ein Schlüssel-Wert-Paar darstellt, valuedas sowohl den Switchnamen als auch den Wert enthält.

    Um mehrere Schalter zu definieren, trennen Sie das Schlüssel-/Wertpaar jedes Schalters im Attribut des <AppContextSwitchOverrides> value Elements mit einem Semikolon. In diesem Fall weist das <AppContextSwitchOverrides> Element das folgende Format auf:

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

    Die Verwendung des <AppContextSwitchOverrides> Elements zum Definieren einer Konfigurationseinstellung hat Anwendungsbereich. Das heißt, es wirkt sich nur auf die Anwendung aus.

    Hinweis

    Informationen zu den durch .NET Framework definierten Schaltern finden Sie im <AppContextSwitchOverrides> Element.

  • Durch Hinzufügen eines Eintrags zur Registrierung. Fügen Sie dem HKLM\SOFTWARE\Microsoft\ einen neuen Zeichenfolgenwert hinzu. NETFramework\AppContext-Unterschlüssel . Legen Sie den Namen des Eintrags auf den Namen des Schalters fest. Legen Sie den Wert auf eine der folgenden Optionen fest: True, true, Falseoder false. Wenn die Laufzeit auf einen anderen Wert trifft, wird der Schalter ignoriert.

    Auf einem 64-Bit-Betriebssystem müssen Sie auch denselben Eintrag zum HKLM\SOFTWARE\Wow6432Node\Microsoft\ hinzufügen. NETFramework\AppContext-Unterschlüssel .

    Die Registrierung zum Definieren eines AppContext Schalters verfügt über einen Computerbereich. Das heißt, es wirkt sich auf jede Anwendung aus, die auf dem Computer ausgeführt wird.

Für ASP.NET- und ASP.NET Core Anwendungen legen Sie einen Schalter fest, indem Sie dem <appSettings> Abschnitt der web.config Datei ein <Add> Element hinzufügen. Beispiel:

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

Wenn Sie denselben Schalter auf mehrere Arten festlegen, ist die Reihenfolge der Rangfolge für die Bestimmung, welche Einstellung die anderen Außerkraftsetzungen außer Kraft setzt:

  1. Die programmgesteuerte Einstellung.

  2. Die Einstellung in der app.config Datei (für .NET Framework Apps) oder der web.config Datei (für ASP.NET Core Apps).

  3. Die Registrierungseinstellung (nur für .NET Framework Apps).

Nachfolgend sehen Sie eine einfache Anwendung, die einen Datei-URI an die Path.GetDirectoryName Methode übergibt. Wenn sie unter .NET Framework 4.6 ausgeführt wird, wird ein ArgumentException Fehler ausgelöst, da file:// es sich nicht mehr um einen gültigen Teil eines Dateipfads handelt.

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()
module Example

open System.IO
open System.Runtime.Versioning

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

Path.GetDirectoryName "file://c/temp/dirlist.txt"
|> printfn "%s"


// 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 <StartupCode$ForConsumers1>.$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()

Um das vorherige Verhalten der Methode wiederherzustellen und die Ausnahme zu verhindern, können Sie die Switch.System.IO.UseLegacyPathHandling Option zur Anwendungskonfigurationsdatei für das Beispiel hinzufügen:

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

Siehe auch

Eigenschaften

BaseDirectory

Ruft den Dateipfad des Basisverzeichnisses ab, das der Assemblyresolver für die Suche nach Assemblys verwendet.

TargetFrameworkName

Ruft den Namen der Frameworkversion ab, auf die die aktuelle Anwendung abzielt.

Methoden

GetData(String)

Gibt den Wert des benannten Datenelements zurück, das der aktuellen Anwendungsdomäne zugewiesen ist.

SetData(String, Object)

Legt den Wert des benannten Datenelements fest, das der aktuellen Anwendungsdomäne zugewiesen ist.

SetSwitch(String, Boolean)

Legt den Wert eines Schalters fest.

TryGetSwitch(String, Boolean)

Versucht, den Wert eines Schalters abzurufen.

Gilt für:

Siehe auch