플랫폼 호환성 분석기

"One .NET": 모든 유형의 애플리케이션을 빌드하기 위한 단일 통합 플랫폼이라는 모토를 들어 보셨을 것입니다. .NET 5 SDK에는 ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin 및 ML.NET가 포함되어 있으며, 향후 더 많은 플랫폼에 대한 지원이 추가될 예정입니다. .NET 5는 .NET의 다양한 플랫폼을 일일이 고려하지 않아도 없는 환경을 제공하기 위해 노력하고 있지만, 기본 OS(운영 체제)를 완전히 추상화하려고 하지는 않습니다. 플랫폼별 API(예: P/Invoke, WinRT 또는 iOS 및 Android용 Xamarin 바인딩)를 계속해서 호출할 수 있습니다.

그러나 한 구성 요소에서 플랫폼별 API를 사용하면 코드는 더 이상 모든 플랫폼에서 작동하지 않을 것입니다. 개발자가 플랫폼별 API를 실수로 사용하는 경우 진단을 받을 수 있도록 디자인 타임에 이를 감지하는 방법이 필요했습니다. 이러한 목표를 달성하기 위해 .NET 5에서 개발자가 적절한 플랫폼별 API를 식별하고 사용하는 데 도움이 되는 플랫폼 호환성 분석기 및 보완 API를 도입했습니다.

새 API의 구성 내용:

  • API에 플랫폼별 주석을 달기 위한 SupportedOSPlatformAttribute와 API에 특정 OS에서 지원되지 않음 주석을 달기 위한 UnsupportedOSPlatformAttribute. 이러한 특성은 선택적으로 버전 번호를 포함할 수 있으며 핵심 .NET 라이브러리의 일부 플랫폼별 API에 이미 적용되어 있습니다.
  • 플랫폼별 API를 안전하게 호출하기 위한 System.OperatingSystem 클래스의 Is<Platform>()Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) 정적 메서드. 예를 들어 OperatingSystem.IsWindows()를 사용하여 Windows 관련 API에 대한 호출을 보호할 수 있으며, OperatingSystem.IsWindowsVersionAtLeast()를 사용하여 버전이 지정된 Windows 관련 API 호출을 보호할 수 있습니다. 이러한 메서드를 플랫폼별 API 참조의 가드로 사용할 수 있는 방법에 대해서는 예제를 참조하세요.

필수 조건

플랫폼 호환성 분석기는 Roslyn 코드 품질 분석기 중 하나입니다. .NET 5부터 이러한 분석기는 .NET SDK에 포함되어 있습니다. 플랫폼 호환성 분석기는 net5.0 이상 버전을 대상으로 하는 프로젝트에서만 기본으로 사용됩니다. 그러나 다른 프레임워크를 대상으로 하는 프로젝트에도 사용할 수 있습니다.

분석기에서 플랫폼 종속성을 확인하는 방법

  • 특성이 지정되지 않은 API모든 OS 플랫폼에서 작동하는 것으로 간주됩니다.

  • [SupportedOSPlatform("platform")]으로 표시된 API는 지정된 플랫폼과 그 하위 집합인 모든 플랫폼에만 이식 가능 것으로 간주됩니다.

    • 이 특성은 다중 플랫폼 지원(예: [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")])을 나타내기 위해 여러 번 적용될 수 있습니다.
    • 플랫폼이 다른 플랫폼의 하위 집합인 경우 특성은 상위 집합 플랫폼도 지원됨을 의미합니다. 예를 들어, [SupportedOSPlatform("iOS")]는 API가 iOS 및 상위 집합 플랫폼인 MacCatalyst에서도 지원된다는 것을 의미합니다.
    • 적절한 플랫폼 컨텍스트 없이 플랫폼별 API를 참조하는 경우 분석기가 경고를 생성합니다.
      • 프로젝트가 지원되는 플랫폼을 대상으로 하지 않는 경우(예: iOS <TargetFramework>net5.0-ios14.0</TargetFramework>를 대상으로 하는 프로젝트에서 호출된 Windows 관련 API) 경고합니다.
      • 프로젝트가 플랫폼 간이고 플랫폼별 API를 호출하는 경우(예: 플랫폼 간 TFM <TargetFramework>net5.0</TargetFramework>에서 호출되는 Windows별 API) 경고합니다.
      • 지정된 플랫폼을 대상으로 하는 프로젝트 내에서 플랫폼별 API가 참조되는 경우(예: 창 <TargetFramework>net5.0-windows</TargetFramework>를 대상으로 하는 프로젝트에서 호출된 Windows 관련 API와 AssemblyInfo.cs 파일 생성이 프로젝트에 대해 사용하도록 설정된 경우) 경고하지 않습니다.
      • 플랫폼별 API 호출이 해당 플랫폼 확인 메서드로 보호되는 경우(예: OperatingSystem.IsWindows()로 보호되는 Windows별 API 호출) 경고하지 않습니다.
      • 플랫폼별 API가 동일한 플랫폼별 컨텍스트에서 참조되는 경우(호출 사이트에도 [SupportedOSPlatform("platform") 특성이 지정됨) 경고하지 않습니다.
  • [UnsupportedOSPlatform("platform")]으로 표시된 API는 지정된 플랫폼 및 해당 API의 하위 집합인 모든 플랫폼에서 지원되지 않는 것으로 간주되지만 다른 모든 플랫폼에서는 지원됩니다.

    • 이 특성은 서로 다른 플랫폼에서 여러 번 적용될 수 있습니다(예: [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")]).
    • 플랫폼이 다른 플랫폼의 하위 집합인 경우 특성은 상위 집합 플랫폼도 지원되지 않음을 의미합니다. 예를 들어, [UnsupportedOSPlatform("iOS")]는 API가 iOS 및 해당 상위 집합 플랫폼인 MacCatalyst에서 지원되지 않음을 의미합니다.
    • 분석기는 platform이 호출 사이트에 유효한 경우에만 경고를 생성합니다.
      • 프로젝트가 지원되지 않는 것으로 지정된 플랫폼을 대상으로 하는 경우(예: 호출 사이트가 <TargetFramework>net5.0-windows</TargetFramework>를 대상으로 할 때 API에 [UnsupportedOSPlatform("windows")] 특성이 지정됨) 경고합니다.

      • 프로젝트가 다중 대상으로 지정되고 platform이 기본 MSBuild <SupportedPlatform> 항목 그룹에 포함되거나 platform이 수동으로 MSBuild<SupportedPlatform> 항목 그룹에 포함된 경우 경고합니다.

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • 지원되지 않는 플랫폼을 대상으로 하지 않거나 다중 대상으로 지정된 앱을 빌드하고 플랫폼이 기본 MSBuild <SupportedPlatform> 항목 그룹에 포함되지 않은 경우 경고하지 않습니다.

  • 두 특성 모두 플랫폼 이름의 일부로 버전 번호를 사용하거나 사용하지 않고 인스턴스화할 수 있습니다. 버전 번호는 major.minor[.build[.revision]] 형식입니다. major.minor는 필수 항목이고 buildrevision 부분은 선택 사항입니다. 예를 들어 "Windows 6.1"은 Windows 버전 6.1을 나타내지만 "Windows"는 Windows 0.0으로 해석됩니다.

자세한 내용은 특성 작동 방식 및 관련 진단 예제를 참조하세요.

분석기가 TFM 대상 플랫폼을 인식하는 방법

분석기는 <TargetFramework> 또는 <TargetFrameworks>와 같은 MSBuild 속성에서 TFM(대상 프레임워크 모니커) 대상 플랫폼을 확인하지 않습니다. TFM에 대상 플랫폼이 있는 경우 MSBuild는 분석기에서 사용하는 AssemblyInfo.cs 파일에 대상 플랫폼 이름을 가진 SupportedOSPlatform 특성을 삽입합니다. 예를 들어, TFM이 net5.0-windows10.0.19041이면 MSBuild는 [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] 특성을 AssemblyInfo.cs 파일에 삽입하며 전체 어셈블리는 Windows 전용으로 간주됩니다. 따라서 버전이 7.0 이하인 Windows 전용 API를 호출해도 프로젝트에 경고가 발생하지 않습니다.

참고 항목

프로젝트에 대해 AssemblyInfo.cs 파일 생성이 사용되지 않는 경우(즉, <GenerateAssemblyInfo> 속성이 false로 설정됨) MSBuild에서 필요한 어셈블리 수준 SupportedOSPlatform 특성을 추가할 수 없습니다. 이 경우 해당 플랫폼을 대상으로 하는 경우에도 플랫폼별 API 사용에 대한 경고를 볼 수 있습니다. 경고를 해결하려면 AssemblyInfo.cs 파일 생성을 사용하도록 설정하거나 프로젝트에 특성을 수동으로 추가합니다.

플랫폼 포함

.NET 6에는 한 플랫폼이 다른 플랫폼의 하위 집합이 될 수 있는 플랫폼 포함 개념이 도입되었습니다. 하위 집합 플랫폼에 대한 주석은 상위 집합 플랫폼에 대한 동일한 지원(또는 지원 부족)을 의미합니다. OperatingSystem 형식의 플랫폼 확인 메서드에 SupportedOSPlatformGuard("supersetPlatform")] 특성이 있는 경우 supersetPlatform은 메서드가 확인하는 OS 플랫폼의 상위 집합으로 간주됩니다.

예를 들어, OperatingSystem.IsIOS() 메서드는 [SupportedOSPlatformGuard("MacCatalyst")]로 간주됩니다. 따라서 다음 설명이 적용됩니다.

  • OperatingSystem.IsIOS()OperatingSystem.IsIOSVersionAtLeast 메서드는 iOS 플랫폼뿐만 아니라 MacCatalyst 플랫폼도 확인합니다.
  • [SupportedOSPlatform("iOS")]는 API가 iOS 및 상위 집합 플랫폼인 MacCatalyst에서도 지원된다는 것을 의미합니다. 이 묵시적인 지원을 제외하려면 [UnsupportedOSPlatform("MacCatalyst")] 특성을 사용할 수 있습니다.
  • [UnsupportedOSPlatform("iOS")는 API가 iOSMacCatalyst에서 지원되지 않음을 의미합니다. [SupportedOSPlatform("MacCatalyst")] 특성을 사용하여 암시적인 지원 부족을 제외할 수 있습니다.

다음 적용 범위 행렬을 고려합니다. 여기서 ✔️는 플랫폼이 지원됨을 나타내고 ❌은 플랫폼이 지원되지 않음함을 나타냅니다.

플랫폼 SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Subset ✔️ ✔️
상위 집합 ✔️ ✔️ ✔️ ✔️

SupportedOSPlatformGuardUnsupportedOSPlatformGuard 특성에도 동일한 규칙이 적용됩니다.

다음 코드 조각은 특성을 결합하여 적절한 지원 수준을 설정하는 방법을 보여 줍니다.

  // MacCatalyst is a superset of iOS therefore supported on iOS and MacCatalyst  
  [SupportedOSPlatform("iOS")]
  public void ApiOnlySupportedOnIOSAndMacCatalyst() { }

  // Does not imply iOS, only supported on MacCatalyst
  [SupportedOSPlatform("MacCatalyst")]
  public void ApiOnlySupportedOnMacCatalyst() { }

  [SupportedOSPlatform("iOS")] // Supported on iOS and MacCatalyst  
  [UnsupportedOSPlatform("MacCatalyst")] // Removes implied MacCatalyst support
  public void ApiOnlySupportedOnIos() { }

  // Unsupported on iOS and MacCatalyst  
  [UnsupportedOSPlatform("iOS")]
  public void ApiUnsupportedOnIOSAndMacCatalyst();

  // Does not imply iOS, only unsupported on MacCatalyst
  [UnsupportedOSPlatform("MacCatalyst")]
  public void ApiUnsupportedOnMacCatalyst() { }

  [UnsupportedOSPlatform("iOS")] // Unsupported on iOS and MacCatalyst  
  [SupportedOSPlatform("MacCatalyst")] // Removes implied MacCatalyst unsupportedness
  public void ApiUnsupportedOnIos() { }

특성 조합에 대한 고급 시나리오

  • [SupportedOSPlatform][UnsupportedOSPlatform] 특성의 조합이 있는 경우 모든 특성은 OS 플랫폼 식별자로 그룹화됩니다.

    • 지원 목록. 각 OS 플랫폼의 가장 낮은 버전이 [SupportedOSPlatform] 특성인 경우 API는 나열된 플랫폼에서만 지원되고 다른 모든 플랫폼에서는 지원되지 않는 것으로 간주됩니다. 각 플랫폼에 대한 선택적 [UnsupportedOSPlatform] 특성은 지원되는 최소 버전보다 상위 버전에만 적용될 수 있으며, 이는 지정된 버전부터 API가 제거됨을 나타냅니다.

      // API is only supported on Windows from version 6.2 to 10.0.19041.0 and all versions of Linux
      // The API is considered not supported for all other platforms.
      [SupportedOSPlatform("windows6.2")]
      [UnsupportedOSPlatform("windows10.0.19041.0")]
      [SupportedOSPlatform("linux")]
      public void ApiSupportedFromWindows80SupportFromCertainVersion();
      
    • 미지원 목록. 각 OS 플랫폼의 가장 낮은 버전이 [UnsupportedOSPlatform] 특성인 경우 API는 나열된 플랫폼에서만 지원되지 않고 다른 모든 플랫폼에서는 지원되는 것으로 간주됩니다. 이 목록에는 동일한 플랫폼의 상위 버전에 [SupportedOSPlatform] 특성이 지정될 수 있습니다. 이는 해당 버전부터 API가 지원됨을 나타냅니다.

      // The API is unsupported on all Linux versions was unsupported on Windows until version 10.0.19041.0.
      // The API is considered supported everywhere else without constraints.
      [UnsupportedOSPlatform("windows")]
      [SupportedOSPlatform("windows10.0.19041.0")]
      [UnsupportedOSPlatform("linux")]
      public void ApiSupportedFromWindows8UnsupportedFromWindows10();
      
    • 불일치 목록. 일부 플랫폼은 가장 낮은 버전이 [SupportedOSPlatform]이고 다른 플랫폼은 가장 낮은 버전이 [UnsupportedOSPlatform]인 경우 불일치로 간주되며 분석기에서 지원되지 않습니다. 불일치가 발생하면 분석기는 [UnsupportedOSPlatform] 플랫폼을 무시합니다.

      • [SupportedOSPlatform][UnsupportedOSPlatform] 특성의 가장 낮은 버전이 동일한 경우 분석기는 해당 플랫폼을 지원 목록의 일부로 간주합니다.
  • 다양한 플랫폼 이름 또는 버전과 함께 플랫폼 특성을 형식, 멤버(메서드, 필드, 속성, 이벤트), 어셈블리에 적용할 수 있습니다.

    • 최상위 수준 target에서 적용된 특성은 모든 멤버 및 형식에 영향을 미칩니다.
    • 자식 수준 특성은 “자식 주석이 플랫폼 지원 범위를 좁힐 수만 있고 확장할 수는 없음” 규칙을 준수하는 경우에만 적용됩니다.
      • 부모에 지원되는 항목만 목록이 있는 경우 자식 멤버 특성을 통해 새 플랫폼 지원을 추가할 수 없습니다(부모 지원 범위가 확장됨). 새 플랫폼 지원은 부모 자체에만 추가할 수 있습니다. 그러나 자식은 동일한 플랫폼의 이후 버전에 Supported 특성을 사용할 수 있습니다(지원 범위가 축소됨). 자식이 동일한 플랫폼에 Unsupported 특성을 사용할 수도 있습니다(이 경우에도 부모 지원 범위가 축소됨).
      • 부모에 지원되지 않는 항목만 목록이 있는 경우 자식 멤버 특성을 통해 새 플랫폼 지원을 추가할 수 있습니다(부모 지원 범위가 축소됨). 그러나 자식은 부모와 동일한 플랫폼에 Supported 특성을 사용할 수 없습니다(부모 지원 범위가 확장됨). 동일한 플랫폼에 대한 지원은 원래 Unsupported 특성이 적용된 부모에만 추가할 수 있습니다.
    • 동일한 platform 이름을 사용하여 API에 [SupportedOSPlatform("platformVersion")]을 두 번 이상 적용한 경우 분석기는 최소 버전을 사용한 항목만 고려합니다.
    • 동일한 platform 이름을 사용하여 API에 [UnsupportedOSPlatform("platformVersion")]을 세 번 이상 적용한 경우 분석기는 가장 이전 버전을 사용한 두 항목만 고려합니다.

    참고 항목

    처음에는 지원되었지만 상위 버전에서 지원되지 않는(제거된) API는 이후 버전에서도 다시 지원되지 않습니다.

특성 작동 방식 및 관련 진단 예제

// An API supported only on Windows all versions.
[SupportedOSPlatform("Windows")]
public void WindowsOnlyApi() { }

// an API supported on Windows and Linux.
[SupportedOSPlatform("Windows")]
[SupportedOSPlatform("Linux")]
public void SupportedOnWindowsAndLinuxOnly() { }

// an API only supported on Windows 6.2 and later, not supported for all other.
// an API is removed/unsupported from version 10.0.19041.0.
[SupportedOSPlatform("windows6.2")]
[UnsupportedOSPlatform("windows10.0.19041.0")]
public void ApiSupportedFromWindows8UnsupportedFromWindows10() { }

// an Assembly supported on Windows, the API added from version 10.0.19041.0.
[assembly: SupportedOSPlatform("Windows")]
[SupportedOSPlatform("windows10.0.19041.0")]
public void AssemblySupportedOnWindowsApiSupportedFromWindows10() { }

public void Caller()
{
    WindowsOnlyApi(); // warns: This call site is reachable on all platforms. 'WindowsOnlyApi()' is only supported on: 'windows'

    // This call site is reachable on all platforms. 'SupportedOnWindowsAndLinuxOnly()' is only supported on: 'Windows', 'Linux'
    SupportedOnWindowsAndLinuxOnly();

    // This call site is reachable on all platforms. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is only supported on: 'windows' from version 6.2 to 10.0.19041.0
    ApiSupportedFromWindows8UnsupportedFromWindows10();

    // for same platform analyzer only warn for the latest version.
    // This call site is reachable on all platforms. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later
    AssemblySupportedOnWindowsApiSupportedFromWindows10();
}

// an API not supported on android but supported on all other.
[UnsupportedOSPlatform("android")]
public void DoesNotWorkOnAndroid() { }

// an API was unsupported on Windows until version 6.2.
// The API is considered supported everywhere else without constraints.
[UnsupportedOSPlatform("windows")]
[SupportedOSPlatform("windows6.2")]
public void StartedWindowsSupportFromVersion8() { }

// an API was unsupported on Windows until version 6.2.
// Then the API is removed (unsupported) from version 10.0.19041.0.
// The API is considered supported everywhere else without constraints.
[UnsupportedOSPlatform("windows")]
[SupportedOSPlatform("windows6.2")]
[UnsupportedOSPlatform("windows10.0.19041.0")]
public void StartedWindowsSupportFrom8UnsupportedFrom10() { }

public void Caller2()
{
    DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'

    // This call site is reachable on all platforms. 'StartedWindowsSupportFromVersion8()' is unsupported on: 'windows' 6.2 and before.
    StartedWindowsSupportFromVersion8();

    // This call site is reachable on all platforms. 'StartedWindowsSupportFrom8UnsupportedFrom10()' is supported on: 'windows' from version 6.2 to 10.0.19041.0
    StartedWindowsSupportFrom8UnsupportedFrom10();
}

보고된 경고 처리

이러한 진단을 처리하는 권장 방법은 적절한 플랫폼에서 실행되는 경우에만 플랫폼별 API를 호출하는 것입니다. 다음은 경고를 해결하는 데 사용할 수 있는 옵션입니다. 상황에 가장 적합한 것을 선택하세요.

  • 호출를 보호합니다. 런타임에 코드를 조건부로 호출하여 이를 달성할 수 있습니다. 플랫폼 확인 방법 중 하나(예: OperatingSystem.Is<Platform>() 또는 OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0))를 사용하여 원하는 Platform에서 실행하고 있는지 확인합니다. 예제.

  • 호출 사이트를 플랫폼별로 표시합니다. 사용자 고유의 API를 플랫폼별로 표시하여 요구 사항을 효과적으로 호출자에게 전달할 수도 있습니다. 참조되는 플랫폼 종속 호출과 동일한 특성을 사용하여 포함하는 메서드나 형식 또는 전체 어셈블리를 표시합니다. .

  • 플랫폼 검사를 사용하여 호출 사이트를 어설션합니다. 런타임에 추가 if 문의 오버헤드를 원친 않는 경우 대신 Debug.Assert(Boolean)를 사용합니다. 예제.

  • 코드를 삭제합니다. Windows 사용자가 코드를 사용할 때 충실도가 상실되다는 의미이므로 일반적으로 개발자가 원하는 옵션은 아닙니다. 플랫폼 간 대안이 있는 경우 플랫폼별 API보다 대안을 사용하는 것이 좋습니다.

  • 경고를 표시하지 않습니다. EditorConfig 항목 또는 #pragma warning disable CA1416을 통해 경고를 표시하지 않을 수도 있습니다. 그러나 플랫폼별 API를 사용하는 경우 이 옵션은 마지막 수단이어야 합니다.

    #pragma 사전 컴파일러 지시문을 사용하여 경고를 사용하지 않도록 설정할 때 대상으로 삼는 식별자는 대/소문자를 구분합니다. 예를 들어, ca1416은 실제로 경고 CA1416을 사용하도록 설정합니다.

가드 메서드를 사용하여 플랫폼별 API를 보호

가드 메서드의 플랫폼 이름은 호출하는 플랫폼 종속 API 플랫폼 이름과 일치해야 합니다. 호출하는 API의 플랫폼 문자열에 버전이 포함되는 경우

  • [SupportedOSPlatform("platformVersion")] 특성의 경우 가드 메서드 플랫폼 version이 호출하는 플랫폼의 Version보다 크거나 같아야 합니다.

  • [UnsupportedOSPlatform("platformVersion")] 특성의 경우 가드 메서드 플랫폼 version이 호출하는 플랫폼의 Version보다 작거나 같아야 합니다.

    public void CallingSupportedOnlyApis() // Allow list calls
    {
        if (OperatingSystem.IsWindows())
        {
            WindowsOnlyApi(); // will not warn
        }
    
        if (OperatingSystem.IsLinux())
        {
            SupportedOnWindowsAndLinuxOnly(); // will not warn, within one of the supported context
        }
    
        // Can use &&, || logical operators to guard combined attributes
        if (OperatingSystem.IsWindowsVersionAtLeast(6, 2) && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)))
        {
            ApiSupportedFromWindows8UnsupportedFromWindows10();
        }
    
        if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0))
        {
            AssemblySupportedOnWindowsApiSupportedFromWindows10(); // Only need to check latest supported version
        }
    }
    
    public void CallingUnsupportedApis()
    {
        if (!OperatingSystem.IsAndroid())
        {
            DoesNotWorkOnAndroid(); // will not warn
        }
    
        if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(6, 2))
        {
            StartedWindowsSupportFromVersion8(); // will not warn
        }
    
        if (!OperatingSystem.IsWindows() || // supported all other platforms
           (OperatingSystem.IsWindowsVersionAtLeast(6, 2) && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)))
        {
            StartedWindowsSupportFrom8UnsupportedFrom10(); // will not warn
        }
    }
    
  • OperatingSystem API를 사용할 수 없는 netstandard 또는 netcoreapp을 대상으로 하는 코드를 보호해야 하는 경우 RuntimeInformation.IsOSPlatform API를 사용할 수 있으며 분석기에 반영됩니다. 하지만 OperatingSystem에 추가된 새 API만큼 최적화되지는 않았습니다. OSPlatform 구조체에서 플랫폼이 지원되지 않는 경우 OSPlatform.Create(String)을 호출하고 플랫폼 이름을 전달할 수 있습니다(이 경우에도 분석기에 반영됨).

    public void CallingSupportedOnlyApis()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            SupportedOnWindowsAndLinuxOnly(); // will not warn
        }
    
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("browser")))
        {
            ApiOnlySupportedOnBrowser(); // call of browser specific API
        }
    }
    

플랫폼 가드 특성으로 API에 주석을 달고 이를 사용자 지정 가드로 사용

이전에 표시된 것처럼 분석기는 OperatingSystem.IsWindowsRuntimeInformation.IsOSPlatform과 같은 OperatingSystem 형식의 플랫폼 보호 정적 메서드를 인식합니다. 그러나 가드 결과를 필드에 캐시하여 재사용하거나 플랫폼 확인을 위해 사용자 지정 가드 방법을 사용할 수 있습니다. 분석기는 이러한 API를 사용자 지정 가드로 인식해야 하며 해당 API로 보호되는 API에 대해 경고해서는 안 됩니다. 이 시나리오를 지원하기 위해 가드 특성이 .NET 6에 도입되었습니다.

  • SupportedOSPlatformGuardAttributeSupportedOSPlatformAttribute 주석이 달린 API에 대한 보호 장치로 사용할 수 있는 API에 주석을 답니다.
  • UnsupportedOSPlatformGuardAttributeUnsupportedOSPlatformAttribute 주석이 달린 API에 대한 보호 장치로 사용할 수 있는 API에 주석을 답니다.

이러한 특성에는 선택적으로 버전 번호가 포함될 수 있습니다. 둘 이상의 플랫폼을 보호하기 위해 여러 번 적용할 수 있으며 필드, 속성 또는 메서드에 주석을 추가하는 데 사용할 수 있습니다.

class Test
{
    [UnsupportedOSPlatformGuard("browser")] // The platform guard attribute
#if TARGET_BROWSER
    internal bool IsSupported => false;
#else
    internal bool IsSupported => true;
#endif

    [UnsupportedOSPlatform("browser")]
    void ApiNotSupportedOnBrowser() { }

    void M1()
    {
        ApiNotSupportedOnBrowser();  // Warns: This call site is reachable on all platforms.'ApiNotSupportedOnBrowser()' is unsupported on: 'browser'

        if (IsSupported)
        {
            ApiNotSupportedOnBrowser();  // Not warn
        }
    }

    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    void ApiOnlyWorkOnWindowsLinux() { }

    [SupportedOSPlatformGuard("Linux")]
    [SupportedOSPlatformGuard("Windows")]
    private readonly bool _isWindowOrLinux = OperatingSystem.IsLinux() || OperatingSystem.IsWindows();

    void M2()
    {
        ApiOnlyWorkOnWindowsLinux();  // This call site is reachable on all platforms.'ApiOnlyWorkOnWindowsLinux()' is only supported on: 'Linux', 'Windows'.

        if (_isWindowOrLinux)
        {
            ApiOnlyWorkOnWindowsLinux();  // Not warn
        }
    }
}

호출 사이트를 플랫폼별로 표시

플랫폼 이름은 호출하는 플랫폼 종속 API와 일치해야 합니다. 플랫폼 문자열에 버전이 포함되는 경우

  • [SupportedOSPlatform("platformVersion")] 특성의 경우 호출 사이트 플랫폼 version이 호출하는 플랫폼의 Version보다 크거나 같아야 합니다.

  • [UnsupportedOSPlatform("platformVersion")] 특성의 경우 호출 사이트 플랫폼 version이 호출하는 플랫폼의 Version보다 작거나 같아야 합니다.

    // an API supported only on Windows.
    [SupportedOSPlatform("windows")]
    public void WindowsOnlyApi() { }
    
    // an API supported on Windows and Linux.
    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    public void SupportedOnWindowsAndLinuxOnly() { }
    
    // an API only supported on Windows 6.2 and later, not supported for all other.
    // an API is removed/unsupported from version 10.0.19041.0.
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")]
    public void ApiSupportedFromWindows8UnsupportedFromWindows10() { }
    
    // an Assembly supported on Windows, the API added from version 10.0.19041.0.
    [assembly: SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("windows10.0.19041.0")]
    public void AssemblySupportedOnWindowsApiSupportedFromWindows10() { }
    
    [SupportedOSPlatform("windows6.2")] // call site attributed Windows 6.2 or above.
    public void Caller()
    {
        WindowsOnlyApi(); // will not warn as call site is for Windows.
    
        // will not warn as call site is for Windows all versions.
        SupportedOnWindowsAndLinuxOnly();
    
        // will not warn for the [SupportedOSPlatform("windows6.2")] attribute, but warns for [UnsupportedOSPlatform("windows10.0.19041.0")]
        // This call site is reachable on: 'windows' 6.2 and later. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is unsupported on: 'windows' 10.0.19041.0 and later.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // The call site version is lower than the calling version, so warns:
        // This call site is reachable on: 'windows' 6.2 and later. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    [SupportedOSPlatform("windows10.0.22000")] // call site attributed with windows 10.0.22000 or above.
    public void Caller2()
    {
        // This call site is reachable on: 'windows' 10.0.22000 and later. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is unsupported on: 'windows' 10.0.19041.0 and later.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // will not warn as call site version higher than calling API.
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")] // call site supports Windows from version 6.2 to 10.0.19041.0.
    public void Caller3()
    {
        // will not warn as caller has exact same attributes.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // The call site reachable for the version not supported in the calling API, therefore warns:
        // This call site is reachable on: 'windows' from version 6.2 to 10.0.19041.0. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later.
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    // an API not supported on Android but supported on all other.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // an API was unsupported on Windows until version 6.2.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows6.2")]
    public void StartedWindowsSupportFromVersion8() { }
    
    // an API was unsupported on Windows until version 6.2.
    // Then the API is removed (unsupported) from version 10.0.19041.0.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")]
    public void StartedWindowsSupportFrom8UnsupportedFrom10() { }
    
    [UnsupportedOSPlatform("windows")] // Caller no support Windows for any version.
    public void Caller4()
    {
        // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
        DoesNotWorkOnAndroid();
    
        // will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFromVersion8();
    
        // same, will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFrom8UnsupportedFrom10();
    }
    
    [UnsupportedOSPlatform("windows")]
    [UnsupportedOSPlatform("android")] // Caller not support Windows and Android for any version.
    public void Caller4()
    {
        DoesNotWorkOnAndroid(); // will not warn as call site not supports Android.
    
        // will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFromVersion8();
    
        // same, will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFrom8UnsupportedFrom10();
    }
    

플랫폼 검사를 사용하여 호출 사이트를 어설션

플랫폼 가드 예제에서 사용되는 모든 조건부 검사는 Debug.Assert(Boolean)에 대한 조건으로 사용할 수도 있습니다.

// An API supported only on Linux.
[SupportedOSPlatform("linux")]
public void LinuxOnlyApi() { }

public void Caller()
{
    Debug.Assert(OperatingSystem.IsLinux());

    LinuxOnlyApi(); // will not warn
}

참고 항목