.NET Standard 来日苦短去日长 (3)

你会得到以下警告:

CA1416: 'RegistryKey.OpenSubKey(string)' is supported on 'windows' CA1416: 'Registry.CurrentUser' is supported on 'windows' CA1416: 'RegistryKey.GetValue(string?)' is supported on 'windows'

你有三个选择来处理这些警告。

调用保护:在调用 API 之前,你可以使用 OperatingSystem.IsWindows() 来检查当前运行环境是否是 Windows 系统。

将调用标记为 Windows 专用:在某些情况下,通过 [SupportedOSPlatform("windows")] 将调用成员标记为特定平台也有一定的意义。

删除代码:一般来说,这不是你想要的,因为这意味着当你的代码被 Windows 用户使用时,你会失去保真度(fidelity)。但对于存在跨平台替代方案的情况,你应该尽可能使用跨平台方案,而不是平台特定的 API。例如,你可以使用一个 XML 配置文件来代替使用注册表。

抑制警告:当然,你可以通过 .editorconfig 或 #pragma warning disable 来抑制警告。然而,当使用特定平台的 API 时,你应该更喜欢选项 (1) 和 (2)。

为了调用保护,可以使用 System.OperatingSystem 类上的新静态方法,示例:

private static string GetLoggingDirectory() { if (OperatingSystem.IsWindows()) { using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam")) { if (key?.GetValue("LoggingDirectoryPath") is string configuredPath) return configuredPath; } } string exePath = Process.GetCurrentProcess().MainModule.FileName; string folder = Path.GetDirectoryName(exePath); return Path.Combine(folder, "Logging"); }

要将你的代码标记为 Windows 专用,请应用新的 SupportedOSPlatform 属性:

[SupportedOSPlatform("windows")] private static string GetLoggingDirectory() { using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam")) { if (key?.GetValue("LoggingDirectoryPath") is string configuredPath) return configuredPath; } string exePath = Process.GetCurrentProcess().MainModule.FileName; string folder = Path.GetDirectoryName(exePath); return Path.Combine(folder, "Logging"); }

在这两种情况下,使用注册表的警告都会消失。

关键的区别在于,在第二个例子中,分析器现在会对 GetLoggingDirectory() 的调用发出警告,因为它现在被认为是 Windows 特有的 API。换句话说,你把平台检查的要求转给调用者放去做了。

[SupportedOSPlatform] 属性可以应用于成员、类型和程序集级别。这个属性也被 BCL 本身使用,例如,程序集 Microsoft.Win32.Registry 就应用了这个属性,这也是分析器最先就知道注册表是 Windows 特定 API 方法的原因。

请注意,如果你的目标是 net5.0-windows,这个属性会自动应用到你的程序集中。这意味着使用 net5.0-windows 的 Windows 专用 API 永远不会产生任何警告,因为你的整个程序集被认为是 Windows 专用的。

处理 Blazor WebAssembly 不支持的 API

Blazor WebAssembly 项目在浏览器沙盒内运行,这限制了你可以使用的 API。例如,虽然线程和进程创建都是跨平台的 API,但我们无法让这些 API 在 Blazor WebAssembly 中工作,它们会抛出 PlatformNotSupportedException。我们已经用 [UnsupportedOSPlatform("browser")] 标记了这些 API。

假设你将 GetLoggingDirectory() 方法复制并粘贴到 Blazor WebAssembly 应用程序中:

private static string GetLoggingDirectory() { //... string exePath = Process.GetCurrentProcess().MainModule.FileName; string folder = Path.GetDirectoryName(exePath); return Path.Combine(folder, "Logging"); }

你将得到以下警告:

CA1416 'Process.GetCurrentProcess()' is unsupported on 'browser' CA1416 'Process.MainModule' is unsupported on 'browser'

你可以用与 Windows 特定 API 基本相同的做法来处理这些警告。

你可以对调用进行保护:

private static string GetLoggingDirectory() { //... if (!OperatingSystem.IsBrowser()) { string exePath = Process.GetCurrentProcess().MainModule.FileName; string folder = Path.GetDirectoryName(exePath); return Path.Combine(folder, "Logging"); } else { return string.Empty; } }

或者你可以将该成员标记为不被 Blazor WebAssembly 支持:

[UnsupportedOSPlatform("browser")] private static string GetLoggingDirectory() { //... string exePath = Process.GetCurrentProcess().MainModule.FileName; string folder = Path.GetDirectoryName(exePath); return Path.Combine(folder, "Logging"); }

由于浏览器沙盒的限制性相当大,所以并不是所有的类库和 NuGet 包都能在 Blazor WebAssembly 中运行。此外,绝大多数的库也不应该支持在 Blazor WebAssembly 中运行。

这就是为什么针对 net5.0 的普通类库不会看到不支持 Blazor WebAssembly API 的警告。你必须在项目文件中添加 <SupportedPlatform> 项,明确表示你打算在 Blazor WebAssembly 中支持您的项目:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <SupportedPlatform Include="browser" /> </ItemGroup> </Project>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjxsj.html