平台兼容性分析器

你可能听说过“一个 .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 包括:

  • SupportedOSPlatformAttribute 用于将 API 批注为特定于平台,UnsupportedOSPlatformAttribute 用于将 API 批注为在特定 OS 上不受支持。 这些属性可以选择包括版本号,并且已应用于核心 .NET 库中的某些特定于平台的 API。
  • System.OperatingSystem 类中的 Is<Platform>()Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) 静态方法,用于安全地调用特定于平台的 API。 例如,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 调用)的保护,则不会生成警告。
      • 如果在相同的特定于平台的上下文(使用 [SupportedOSPlatform("platform") 属性化的调用站点)中引用特定于平台的 API,则不会生成警告。
  • 标记为 [UnsupportedOSPlatform("platform")] 的 API 视为在指定的平台上以及以其为子集的任何平台上不受支持,但在所有其他平台上都受支持。

    • 可以使用不同平台(例如 [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")])多次应用属性。
    • 如果该平台是另一个平台的一部分,则该特性意味着该超集平台也不受支持。 例如,[UnsupportedOSPlatform("iOS")] 意味着 API 在 iOS 上及其超集平台 MacCatalyst 上均不受支持。
    • 仅当 platform 对调用站点有效时,分析器才会生成警告
      • 如果项目面向被属性化为不受支持的平台(例如,如果 API 使用 [UnsupportedOSPlatform("windows")] 进行了属性化,且调用站点面向 <TargetFramework>net5.0-windows</TargetFramework>),则将生成警告。

      • 如果项目面向多个平台,且 platform 包含在默认 MSBuild <SupportedPlatform> 项组中,或者 platform 手动包含在 MSBuild<SupportedPlatform> 项组中,则将生成警告:

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • 如果要生成的应用不面向不受支持的平台或是多定向的,并且平台未包含在默认 MSBuild 项组中,则不会生成警告。

  • 可以使用或不使用作为平台名称一部分的版本号对两个属性进行实例化。 版本号的格式为 major.minor[.build[.revision]]major.minor 是必需的,而 buildrevision 部分是可选的。 例如,“Windows6.1”指示 Windows 版本 6.1,但“Windows”被解释为 Windows 0.0。

有关详细信息,请参阅属性的工作方式及其导致的诊断的示例

分析器如何识别 TFM 目标平台

分析器不会检查来自 MSBuild 属性的目标框架名字对象 (TFM) 目标平台<TargetFramework><TargetFrameworks>。 如果 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") 意味着 iOSMacCatalyst 不支持 API。 可以使用 [SupportedOSPlatform("MacCatalyst")] 特性排除这一隐含的支持缺失。

考虑下面的覆盖率矩阵,其中 ✔️ 指示平台受支持,而 ❌ 指示平台不受支持。

平台 SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
子集
超集

提示

相同的规则也适用于 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")] 一次以上,则分析器仅考虑最低版本的 API。
    • 如果对具有相同 platform 名称的 API 应用 [UnsupportedOSPlatform("platformVersion")] 两次以上,则分析器仅考虑最早版本的两个 API。

    注意

    最初受支持但在更高版本中不受支持(删除)的 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。 下面是可用于解决警告的选项;选择最适合你的情况的选项:

  • 保护调用。 可以通过在运行时有条件地调用代码来实现此目的。 使用平台检查方法之一检查是否正在所需的 Platform 上运行,例如 OperatingSystem.Is<Platform>()OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)示例

  • 将调用站点标记为特定于平台。 还可以选择将自己的 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 不可用的 netstandardnetcoreapp 的代码,则可以使用 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 类型中的平台保护静态方法,例如 OperatingSystem.IsWindows,还有 RuntimeInformation.IsOSPlatform。 但是,你可能想要将保护结果缓存在字段中,并重复使用它,或者使用自定义保护方法来检查平台。 分析器需要将此类 API 识别为自定义保护,且不能针对它们保护的 API 发出警告。 .NET 6 中引入了保护属性以支持此方案:

这些特性可选择性地包含版本号。 可以多次应用这些特性来保护多个平台,并可用于批注字段、属性或方法。

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
}

另请参阅