CA1416:驗證平台相容性
值 | |
---|---|
規則識別碼 | CA1416 |
類別 | 互通性 |
修正是中斷或非中斷 | 非中斷 |
原因
如果平臺特定 API 用於不同平臺的內容,或平臺未驗證 (平臺中性) ,則會報告違規。 如果使用專案的目標平臺不支援的 API,也會報告違規。
此規則預設只會針對以 .NET 5 或更新版本為目標的專案啟用。 不過,您可以針對以其他架構為目標的專案 啟用 它。
規則描述
.NET 5 已新增屬性 SupportedOSPlatformAttribute 和 UnsupportedOSPlatformAttribute ,以標注平臺特定 API。 這兩個屬性都可以在平臺名稱中具現化或不含版本號碼。 您也可以使用不同的平臺多次套用它們。
- 未批註的 API 會被視為在所有作業系統 (作業系統) 平臺上運作。
- 標示為 的
[SupportedOSPlatform("platformName")]
API 只會被視為可移植到指定的 OS 平臺。 如果平臺是 另一個平臺的子集,則屬性工作表示也支援該平臺。 - 在指定的 OS 平臺上,標示為 的
[UnsupportedOSPlatform("platformName")]
API 會被視為不受支援。 如果平臺是 另一個平臺的子集,則屬性工作表示該平臺也不受支援。
您可以在單一 API 上結合 [SupportedOSPlatform]
和 [UnsupportedOSPlatform]
屬性。 在此情況下,會套用以下規則:
- 允許清單。 如果每個 OS 平臺的最低版本是
[SupportedOSPlatform]
屬性,則 API 只會被列出的平臺支援,而且所有其他平臺都不支援。 此清單可以有具有相同[UnsupportedOSPlatform]
平臺的屬性,但只有較高版本,這表示 API 已從該版本中移除。 - 拒絕清單。 如果每個 OS 平臺的最低版本是
[UnsupportedOSPlatform]
屬性,則 API 只會被列出的平臺支援,而且所有其他平臺都支援。 此清單可以有具有相同[SupportedOSPlatform]
平臺的屬性,但只有較高版本,這表示自該版本以來支援 API。 - 不一致的清單。 如果某些平臺的最低版本是
[SupportedOSPlatform]
,但[UnsupportedOSPlatform]
對於其他平臺而言,此組合會被視為不一致。 會忽略 API 上的一些批註。 未來,我們可能會引進分析器,以在不一致的情況下產生警告。
如果您從不同平臺的內容存取以這些屬性標注的 API,您可以看到 CA1416 違規。
TFM 目標平臺
分析器不會從 MSBuild 屬性檢查目標架構 Moniker (TFM) 目標平臺,例如 <TargetFramework>
或 <TargetFrameworks>
。 如果 TFM 具有目標平臺,.NET SDK 會在 Analyzer 所取用的AssemblyInfo.cs檔案中插入 SupportedOSPlatform
具有目標平臺名稱的屬性。 例如,如果 TFM 為 net5.0-windows10.0.19041
,SDK 會將 屬性插入 [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")]
AssemblyInfo.cs 檔案中,而且整個元件只會被視為 Windows。 因此,呼叫以 7.0 或更新版本設定的僅限 Windows API 並不會在專案中造成任何警告。
注意
如果專案 (停用 AssemblyInfo.cs 檔案產生,屬性 <GenerateAssemblyInfo>
會設定為 false
) ,SDK 無法新增必要的元件層級 SupportedOSPlatform
屬性。 在此情況下,即使您是以該平臺為目標,您仍可以看到平臺特定 API 使用量的警告。 若要解決警告,請啟用 AssemblyInfo.cs 檔案產生,或在專案中手動新增 屬性。
違規
如果您只存取指定平臺上支援的 API, (
[SupportedOSPlatform("platformName")]
從其他平臺上可連線的程式碼) ,您會看到下列違規: 'platformName' 上支援 '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. }
注意
只有在專案未以支援的平臺 ()
net5.0-differentPlatform
為目標時,才會發生違規。 這也適用于多目標專案。 如果專案以指定的平臺 ()net5.0-platformName
為目標,且已啟用專案的 AssemblyInfo.cs 檔案產生,則不會發生違規。從以不支援平臺為目標的內容存取所屬性
[UnsupportedOSPlatform("platformName")]
的 API 可能會產生違規: 'API' 在 '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
和多重目標排除程式碼,或在執行時間有條件地呼叫程式碼來達成此目的。 分析器會辨識 類別和 System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform 中的 OperatingSystem 平臺防護。
使用 或 標注 SupportedOSPlatformGuardAttributeUnsupportedOSPlatformGuardAttribute 的標準平臺防護方法或自訂防護 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