Share via


CA1416: 플랫폼 호환성 유효성 검사

속성
규칙 ID CA1416
제목 플랫폼 호환성 유효성 검사
범주 상호 운용성
수정 사항이 주요 변경인지 여부 주요 변경 아님
.NET 8에서 기본적으로 사용 경고로

원인

플랫폼별 API가 다른 플랫폼의 컨텍스트에서 사용되거나 플랫폼이 확인되지 않은 경우(플랫폼 중립적) 위반이 보고됩니다. 프로젝트의 대상 플랫폼에 대해 지원되지 않는 API가 사용되는 경우에도 위반이 보고됩니다.

.NET 5 이상을 대상으로 하는 프로젝트의 경우 이 규칙이 기본적으로 사용하도록 설정되어 있습니다. 그러나 다른 프레임워크를 대상으로 하는 프로젝트에도 사용할 수 있습니다.

규칙 설명

.NET 5는 플랫폼별 API에 주석을 달기 위해 새 특성을 SupportedOSPlatformAttribute 추가했습니다 UnsupportedOSPlatformAttribute. 두 특성 모두 플랫폼 이름의 일부로 버전 번호를 사용하거나 사용하지 않고 인스턴스화할 수 있습니다. 두 특성을 서로 다른 플랫폼에서 여러 번 적용할 수 있습니다.

  • 주석이 없는 API는 모든 OS(운영 체제) 플랫폼에서 작동하는 것으로 간주됩니다.
  • [SupportedOSPlatform("platformName")]으로 표시된 API는 지정된 OS 플랫폼에만 이식할 수 있는 것으로 간주됩니다. 플랫폼이 다른 플랫폼의 하위 집합인 경우 이 특성은 해당 플랫폼도 지원됨을 의미합니다.
  • [UnsupportedOSPlatform("platformName")]으로 표시된 API는 지정된 OS 플랫폼에서 지원되지 않는 것으로 간주됩니다. 플랫폼이 다른 플랫폼의 하위 집합인 경우 이 특성은 해당 플랫폼도 지원되지 않음을 의미합니다.

단일 API에서 [SupportedOSPlatform][UnsupportedOSPlatform] 특성을 결합할 수 있습니다. 이 경우 다음 규칙이 적용됩니다.

  • 허용 목록. 각 OS 플랫폼의 가장 낮은 버전이 [SupportedOSPlatform] 특성인 경우 API는 나열된 플랫폼에서만 지원되고 다른 모든 플랫폼에서는 지원되지 않는 것으로 간주됩니다. 이 목록에는 동일한 플랫폼이지만 더 상위 버전이 지정된 [UnsupportedOSPlatform] 특성이 포함될 수 있습니다. 이는 해당 버전부터 API가 제거됨을 나타냅니다.
  • 거부 목록. 각 OS 플랫폼의 가장 낮은 버전이 [UnsupportedOSPlatform] 특성인 경우 API는 나열된 플랫폼에서만 지원되지 않고 다른 모든 플랫폼에서는 지원되는 것으로 간주됩니다. 이 목록에는 동일한 플랫폼이지만 더 상위 버전이 지정된 [SupportedOSPlatform] 특성이 포함될 수 있습니다. 이는 해당 버전부터 API가 지원됨을 나타냅니다.
  • 불일치 목록. 일부 플랫폼의 최하위 버전은 [SupportedOSPlatform]이지만 다른 플랫폼에 대해서는 [UnsupportedOSPlatform]인 경우 이 조합은 일관성이 없는 것으로 간주됩니다. API의 일부 주석은 무시됩니다. 향후에는 불일치가 발생할 경우 경고를 생성하는 분석기를 도입할 수 있습니다.

다른 플랫폼의 컨텍스트에서 이러한 특성으로 주석이 추가된 API에 액세스하는 경우 CA1416 위반이 표시될 수 있습니다.

TFM 대상 플랫폼

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

참고 항목

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

위반

  • 다른 플랫폼에서 연결할 수 있는 코드에서 지정된 플랫폼([SupportedOSPlatform("platformName")])에서만 지원되는 API에 액세스하면 ‘API’ is supported on ‘platformName’ 위반이 표시됩니다.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    // API is supported on Windows, iOS from version 14.0, and MacCatalyst from version 14.0.
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")] // MacCatalyst is a superset of iOS, therefore it's also supported.
    public void SupportedOnWindowsIos14AndMacCatalyst14() { }
    
    public void Caller()
    {
        LinuxOnlyApi(); // This call site is reachable on all platforms. 'LinuxOnlyApi()' is only supported on: 'linux'
    
        SupportedOnWindowsIos14AndMacCatalyst14(); // This call site is reachable on all platforms. 'SupportedOnWindowsIos14AndMacCatalyst14()'
                                                   // is only supported on: 'windows', 'ios' 14.0 and later, 'MacCatalyst' 14.0 and later.
    }
    

    참고 항목

    위반은 프로젝트가 지원되는 플랫폼(net5.0-differentPlatform)을 대상으로 하지 않는 경우에만 발생합니다. 이는 다중 대상 프로젝트에도 적용됩니다. 프로젝트가 지정된 플랫폼(net5.0-platformName)을 대상으로 하고 AssemblyInfo.cs 파일 생성이 프로젝트에서 사용 설정된 경우 위반이 발생하지 않습니다.

  • 지원되지 않는 플랫폼을 대상으로 하는 컨텍스트에서 [UnsupportedOSPlatform("platformName")] 특성이 지정된 API에 액세스하면 ‘API’ is unsupported on ‘platformName’ 위반이 발생할 수 있습니다.

    // An API not supported on Android but supported on all other platforms.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // An API was unsupported on Windows until version 10.0.18362.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion() { }
    
    public void Caller()
    {
        DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
    
        StartedWindowsSupportFromCertainVersion(); // This call site is reachable on all platforms. 'StartedWindowsSupportFromCertainVersion()' is unsupported on: 'windows' 10.0.18362 and before
    }
    

참고 항목

지원되지 않는 플랫폼을 대상으로 하지 않는 앱을 빌드하는 경우 위반이 발생하지 않습니다. 위반은 다음과 같은 경우에만 발생합니다.

  • 이 프로젝트는 지원되지 않는 것으로 지정된 플랫폼을 대상으로 합니다.

  • platformName이 기본 MSBuild <SupportedPlatform> 항목 그룹에 포함된 경우.

  • platformName가 MSBuild <SupportedPlatform> 항목 그룹에 수동으로 포함된 경우.

    <ItemGroup>
        <SupportedPlatform Include="platformName" />
    </ItemGroup>
    

위반 문제를 해결하는 방법

이러한 위반을 처리하는 권장 방법은 적절한 플랫폼에서 실행되는 경우에만 플랫폼별 API를 호출하는 것입니다. 빌드 시간에 #if 및 다중 대상 지정을 사용하거나 런타임에 코드를 조건부로 호출하여 코드를 제외하여 이를 달성할 수 있습니다. 분석기는 OperatingSystem 클래스 및 System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform에서 플랫폼 가드를 인식합니다.

  • SupportedOSPlatformGuardAttribute 또는 UnsupportedOSPlatformGuardAttribute를 사용하여 주석이 달린 표준 플랫폼 가드 메서드 또는 사용자 지정 가드 API로 호출 사이트를 둘러싸서 위반을 표시하지 않습니다.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    // API is supported on Windows, iOS from version 14.0, and MacCatalyst from version 14.0.
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")] // MacCatalyst is a superset of iOS, therefore it's also supported.
    public void SupportedOnWindowsIos14AndMacCatalyst14() { }
    
    public void Caller()
    {
        LinuxOnlyApi(); // This call site is reachable on all platforms. 'LinuxOnlyApi()' is only supported on: 'linux'.
    
        SupportedOnWindowsIos14AndMacCatalyst14(); // This call site is reachable on all platforms. 'SupportedOnWindowsIos14AndMacCatalyst14()'
                                                   // is only supported on: 'windows', 'ios' 14.0 and later, 'MacCatalyst' 14.0 and later.
    }
    
    [SupportedOSPlatformGuard("windows")]  // The platform guard attributes used
    [SupportedOSPlatformGuard("ios14.0")]
    private readonly bool _isWindowOrIOS14 = OperatingSystem.IsWindows() || OperatingSystem.IsIOSVersionAtLeast(14);
    
    // The warnings are avoided using platform guard methods.
    public void Caller()
    {
        if (OperatingSystem.IsLinux()) // standard guard examples
        {
            LinuxOnlyApi(); // no diagnostic
        }
    
        if (OperatingSystem.IsIOSVersionAtLeast(14))
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    
        if (_isWindowOrMacOS14) // custom guard example
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    }
    
    // An API not supported on Android but supported on all other platforms.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // An API was unsupported on Windows until version 10.0.18362.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion();
    
    public void Caller()
    {
        DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
    
        StartedWindowsSupportFromCertainVersion(); // This call site is reachable on all platforms. 'StartedWindowsSupportFromCertainVersion()' is unsupported on: 'windows' 10.0.18362 and before.
    }
    
    [UnsupportedOSPlatformGuard("android")] // The platform guard attribute
    bool IsNotAndroid => !OperatingSystem.IsAndroid();
    
    public void Caller()
    {
        if (!OperatingSystem.IsAndroid()) // using standard guard methods
        {
            DoesNotWorkOnAndroid(); // no diagnostic
        }
    
        // Use the && and || logical operators to guard combined attributes.
        if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(10, 0, 18362))
        {
            StartedWindowsSupportFromCertainVersion(); // no diagnostic
        }
    
        if (IsNotAndroid) // custom guard example
        {
            DoesNotWorkOnAndroid(); // no diagnostic
        }
    }
    
  • 또한 분석기는 System.Diagnostics.Debug.Assert를 지원되지 않는 플랫폼에서 코드에 도달할 수 없도록 하는 수단으로 인식합니다. Debug.Assert를 사용하면 원하는 경우 검사를 릴리스 빌드에서 트리밍할 수 있습니다.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    public void Caller()
    {
        Debug.Assert(OperatingSystem.IsLinux());
    
        LinuxOnlyApi(); // No diagnostic
    }
    
  • 사용자 고유의 API를 플랫폼별로 표시하여 요구 사항을 효과적으로 호출자에게 전달할 수 있습니다. 다음과 같은 API에 플랫폼 특성을 적용할 수 있습니다.

    • 유형
    • 멤버(메서드, 필드, 속성 및 이벤트)
    • 어셈블리
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")]
    public void SupportedOnWindowsAndIos14() { }
    
    [SupportedOSPlatform("ios15.0")] // call site version should be equal to or higher than the API version
    public void Caller()
    {
        SupportedOnWindowsAndIos14(); // No diagnostics
    }
    
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion();
    
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void Caller()
    {
        StartedWindowsSupportFromCertainVersion(); // No diagnostics
    }
    
  • 어셈블리 수준 또는 형식 수준 특성이 적용되면 어셈블리 또는 형식 내의 모든 멤버는 플랫폼별로 간주됩니다.

    [assembly:SupportedOSPlatform("windows")]
    public namespace ns
    {
        public class Sample
        {
            public void SupportedOnWindows() { }
    
            public void Caller()
            {
                SupportedOnWindows(); // No diagnostic as call site and calling method both windows only
            }
        }
    }
    

경고를 표시하지 않는 경우

적절한 플랫폼 컨텍스트 또는 가드 없이 플랫폼별 API를 참조하는 것은 권장하지 않습니다. 그러나 이러한 진단 사용하거나 NoWarn 컴파일러 플래그를 사용 #pragma 하거나 규칙의 심각도를 .editorconfig 파일로 설정하여 표시하지 않을 none 수 있습니다.

[SupportedOSPlatform("linux")]
public void LinuxOnlyApi() { }

public void Caller()
{
#pragma warning disable CA1416
    LinuxOnlyApi();
#pragma warning restore CA1416
}

분석할 코드 구성

분석기는 .NET 5 이상 버전을 대상으로 하고 AnalysisLevel이 5 이상인 프로젝트에 대해서만 기본적으로 사용하도록 설정됩니다. 프로젝트의 .editorconfig 파일에 다음 키-값 쌍을 추가하여 net5.0 이하의 대상 프레임워크에 대해 분석기를 사용하도록 설정할 수 있습니다.

dotnet_code_quality.enable_platform_analyzer_on_pre_net5_target = true

참고 항목