AppContext 클래스

정의

애플리케이션의 컨텍스트에 대한 데이터를 설정 및 검색하기 위한 멤버를 제공합니다.

public ref class AppContext abstract sealed
public static class AppContext
type AppContext = class
Public Class AppContext
상속
AppContext

설명

AppContext 클래스를 사용하면 라이브러리 작성기가 사용자에게 새 기능에 대한 균일한 옵트아웃 메커니즘을 제공할 수 있습니다. 옵트아웃(opt out) 요청을 전달하기 위해 구성 요소 간에 느슨하게 결합된 계약을 설정합니다. 이 기능은 일반적으로 기존 기능이 변경될 때 중요합니다. 반대로, 새로운 기능에 대한 암시적 옵트인(opt in)은 이미 있습니다.

라이브러리 개발자를 위한 AppContext

라이브러리는 클래스를 AppContext 사용하여 호환성 스위치를 정의하고 노출하는 반면, 라이브러리 사용자는 이러한 스위치를 설정하여 라이브러리 동작에 영향을 줄 수 있습니다. 기본적으로 라이브러리는 새로운 기능을 제공하며 스위치가 설정된 경우에만 변경합니다(즉, 이전 기능 제공). 이렇게 하면 라이브러리가 기존 API에 대한 새 동작을 제공하는 동시에 이전 동작에 의존하는 호출자를 계속 지원할 수 있습니다.

스위치 이름 정의

라이브러리 소비자가 동작 변경을 옵트아웃하도록 허용하는 가장 일반적인 방법은 명명된 스위치를 정의하는 것입니다. 해당 value 요소는 스위치 Boolean 의 이름과 해당 값으로 구성된 이름/값 쌍입니다. 기본적으로 스위치는 항상 암시적으로 false새 동작을 제공하며 기본적으로 새 동작을 옵트인합니다. 스위치를 사용하도록 설정하면 true 레거시 동작이 제공됩니다. 스위치를 명시적으로 설정하여 false 새 동작도 제공합니다.

라이브러리에서 공개하는 공식 계약이므로 스위치 이름에 일관된 형식을 사용하는 것이 좋습니다. 다음은 두 가지 명백한 형식입니다.

  • Switch.namespace.switchname

  • Switch.library.switchname

스위치를 정의하고 문서화하면 호출자는 메서드를 프로그래밍 방식으로 호출 AppContext.SetSwitch(String, Boolean) 하여 사용할 수 있습니다. .NET Framework 앱은 애플리케이션 구성 파일에 요소를 추가 <AppContextSwitchOverrides> 하거나 레지스트리를 사용하여 스위치를 사용할 수도 있습니다. 호출자가 구성 스위치의 AppContext 값을 사용하고 설정하는 방법에 대한 자세한 내용은 라이브러리 소비자에 대한 AppContext 섹션을 참조하세요.

.NET Framework 공용 언어 런타임이 애플리케이션을 실행하면 레지스트리의 호환성 설정을 자동으로 읽고 애플리케이션 구성 파일을 로드하여 애플리케이션 인스턴스 AppContext 를 채웁니다. 인스턴스는 AppContext 호출자 또는 .NET Framework 런타임에 의해 프로그래밍 방식으로 채워지므로 .NET Framework 앱은 인스턴스를 구성 AppContext 하기 위해 메서드 호출 SetSwitch 과 같은 작업을 수행할 필요가 없습니다.

설정을 확인합니다.

소비자가 스위치 값을 선언했는지 확인하고 메서드를 호출하여 적절하게 작동할 AppContext.TryGetSwitch 수 있습니다. 메서드는 인수가 switchName 발견되면 반환 true 되고 메서드가 반환되면 해당 isEnabled 인수는 스위치의 값을 나타냅니다. 그렇지 않은 경우 메서드는 false를 반환합니다.

예제

다음 예제에서는 고객이 라이브러리 메서드의 AppContext 원래 동작을 선택할 수 있도록 클래스를 사용하는 방법을 보여 줍니다. 다음은 이름이 StringLibrary1.0인 라이브러리의 버전 1.0입니다. 더 큰 문자열 내에서 부분 문자열의 시작 인덱스를 결정하기 위해 서수 비교를 수행하는 메서드를 정의 SubstringStartsAt 합니다.

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

다음 예제에서는 라이브러리를 사용하여 "고고학자"에서 부분 문자열 "archæ"의 시작 인덱스 찾기를 찾습니다. 메서드가 서수 비교를 수행하므로 부분 문자열을 찾을 수 없습니다.

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'

그러나 라이브러리 버전 2.0은 문화권 구분 비교를 SubstringStartsAt 사용하도록 메서드를 변경합니다.

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

앱이 라이브러리의 새 버전에 대해 실행되도록 다시 컴파일되면 이제 부분 문자열 "archæ"가 "고고학자"의 인덱스 4에서 발견되었다고 보고합니다.

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

이 변경은 스위치를 정의하여 원래 동작에 의존하는 애플리케이션을 중단하지 않도록 방지할 수 있습니다. 이 경우 스위치의 이름은 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 앱에는 스위치의 값을 설정하는 추가 방법이 있습니다.

  • app.config 파일의 섹션에 요소를 <runtime> 추가 <AppContextSwitchOverrides> 합니다. 스위치에는 단일 특성이 있으며, value이 값은 스위치 이름과 해당 값을 모두 포함하는 키/값 쌍을 나타내는 문자열입니다.

    여러 스위치를 정의하려면 요소 value 특성에서 각 스위치의 키/값 쌍을 <AppContextSwitchOverrides> 세미콜론으로 구분합니다. 이 경우 요소의 <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>

둘 이상의 방법으로 동일한 스위치를 설정하는 경우 다른 설정을 재정의하는 우선 순위는 다음과 같습니다.

  1. 프로그래밍 방식 설정입니다.

  2. app.config 파일(.NET Framework 앱의 경우) 또는 web.config 파일(ASP.NET Core 앱의 경우)의 설정입니다.

  3. 레지스트리 설정(.NET Framework 앱에만 해당).

다음은 파일 URI를 전달 하는 간단한 애플리케이션에는 Path.GetDirectoryName 메서드. .NET Framework 4.6에서 실행하면 파일 경로의 유효한 부분이 더 이상 없기 때문에 file:// throw됩니다ArgumentException.

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

메서드의 이전 동작을 복원 하 고 예외를 방지 하려면 추가 Switch.System.IO.UseLegacyPathHandling 예제 애플리케이션 구성 파일에 전환:

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

추가 정보

속성

BaseDirectory

어셈블리 확인자에서 어셈블리를 조사하는 데 사용하는 기본 디렉터리의 파일 경로를 가져옵니다.

TargetFrameworkName

현재 애플리케이션의 대상인 프레임워크 버전의 이름을 가져옵니다.

메서드

GetData(String)

현재 애플리케이션 도메인에 할당되어 있는 명명된 데이터 요소의 값을 반환합니다.

SetData(String, Object)

현재 애플리케이션 도메인에 할당된 명명된 데이터 요소의 값을 설정합니다.

SetSwitch(String, Boolean)

스위치의 값을 설정합니다.

TryGetSwitch(String, Boolean)

스위치의 값을 가져오려고 합니다.

적용 대상

추가 정보