.NET Standard 来日苦短去日长

作者:Richard

翻译:精致码农-王亮

原文:http://dwz.win/Q4h

自从 .NET 5 宣贯以来,很多人都在问这对 .NET Standard 意味着什么,它是否仍然重要。在这篇文章中,我将解释 .NET 5 是如何改进代码共用并取代 .NET Standard 的,我还将介绍什么情况下你仍然需要 .NET Standard。

概要

.NET 5 将是一个具有统一功能和 API 的单一产品,可用于 Windows 桌面应用程序、跨平台移动应用程序、控制台应用程序、云服务和网站。

为了更好地说明这一点,我们更新了这篇[1]关于 TFM (Target Framework Names) 介绍的文章(译文:.NET 5 中 Target Framework 详解),现支持的 TFM 如下:

  • .net5.0,表示代码可在任意平台运行,它合并并替换了 netcoreappnetstandard 这两个名称。这个 TFM 通常只包括跨平台的技术(除了一些为了满足实用性而作出让步的 API,就像我们在 .NET Standard 中所做的那样)。

  • net5.0-windows(还有后面会增加的net6.0-androidnet6.0-ios),这些 TFM 表示 .NET 5 特定于操作系统的风格,包含 net5.0 和特定于操作系统的功能。

我们不会再发布 .NET Standard 的新版本,但是 .NET 5 和所有未来的版本将继续支持 .NET Standard 2.1 和更早的版本。你应该将 net5.0(和未来的版本)视为共享代码的基础。

由于 net5.0 是所有这些新 TFM 的共用的基础,这意味着运行时、库和新的语言特性都会围绕这个版本号进行协调。例如,为了使用 C# 9,你需要使用 net5.0net5.0-windows

如何选择 Target

.NET 5 和所有未来的版本将继续支持 .NET Standard 2.1 和更早的版本,从 .NET Standard 重新 Target 到 .NET 5 的唯一原因是为了获得更多运行时特性、语言特性或 API 支持。所以,你可以把 .NET 5 想象成 .NET Standard 的 vNext。

那新代码呢?该从 .NET Standard 2.0 开始还是直接从 .NET 5 开始?这得视情况而定。

  • 应用程序组件,如果你要将你的应用程序以类库的形式分解成多个组件,我建议将 netX.Y 作为 TFM,netX.Y 中的 X.Y 是应用程序(或多个应用程序)的 .NET 最低版本号。为了简单起见,你可能希望所有组成你的应用程序的 Project 都使用相同的 .NET 版本,因为这样可以保证各处的代码都可以使用相同的 BCL 特性。

  • 可重用库,如果你正在构建计划在 NuGet 上发布的可重用库,你将需要考虑适用范围和可用新特性之间的权衡。.NET Standard 2.0 是 .NET Framework 支持的最高 .NET Standard 版本,所以它可以满足你的大部分使用场景。我们通常建议不要将 Target 锁定在 .NET Standard 1.x 上,因为不值得再为此增添不必要的麻烦。如果你不需要支持 .NET Framwork,那么你可以选择 .NET Standard 2.1 或者 .NET 5,大多数代码可能可以跳过 .NET Standard 2.1 直接转到 .NET 5。

那么,你应该怎么做呢?我的建议是,已被广泛使用的库可能需要同时提供 .NET Standard 2.0 和 .NET 5 支持。支持 .NET Standard 2.0 将使你的库适用性更广,而支持 .NET 5 则确保你可以为已经在 .NET 5 上的用户使用最新的平台特性。

几年后,可重用库的选择将只涉及 netX.Y 版本,这基本上是构建 .NET 库的一惯做法——你通常要支持一段时间较老的版本,以确保没有升级最新 .NET 版本的用户依然可以使用你的库。

总结一下:

  • 在 .NET Framework 和所有其他平台之间共享代码,使用 netstandard2.0

  • 在 Mono、Xamarin 和 .NET Core 3.x 之间共享代码,使用 netstandard2.1

  • 往后的共享代码,使用 net5.0

.NET 5 如何解决 .NET Standard 存在的问题

.NET Standard 使得创建适用于所有 .NET 平台的库变得更加容易,但是 .NET Standard 仍然存在三个问题:

  1. 它的版本更新很慢[2],这意味着你不能轻松地使用最新的特性。

  2. 它需要一个解码环[3]来将版本映射到 .NET 实现。

  3. 它公开了特定于平台的特性[4],这意味着你不能静态地验证代码是否真正可移植。

让我们看看 .NET 5 将如何解决这三个问题。

问题 1:.NET Standard 版本更新慢

在设计 .NET Standard[5] 时,.NET 平台还没有在实现层次上融合,这使得编写需要在不同环境下工作的代码变得困难,因为不同的工作代码使用的是不同的 .NET 实现。

.NET Standard 的目标是统一基础类库(BCL)的特性集,这样你就可以编写一个可以在任何地方运行的单一库。这为我们提供了很好的服务:前 1000 个软件包中有超过 77% 支持 .NET Standard。如果我们看看 NuGet.org 上所有在过去 6 个月里更新过的软件包,采用率是 58%。

但是只标准化 API 就会产生额外的付出,它要求我们在添加新 API 时进行协调——这一直在发生。.NET 开源社区(包括.NET 团队)通过提供新的语言特性、可用性改进、新的交叉(cross-cutting)功能(如 Span<T>)或支持新的数据格式或网络协议,不断对 BCL 进行创新。

而我们虽然可以以 NuGet 包的形式提供新的类型,但不能以这种方式在现有类型上提供新的 API。所以,从一般意义上讲,BCL 的创新需要发布新版本的 .NET 标准。

在 .NET Standard 2.0 之前,这并不是一个真正的问题,因为我们只对现有的 API 进行标准化。但在 .NET Standard 2.1 中,我们对全新的 API 进行了标准化,这也是我们看到相当多摩擦的地方。

这种摩擦从何而来?

.NET 标准是一个 API 集,所有的.NET 实现都必须支持,所以它有一个编辑方面[6]的问题,所有的 API 必须由 .NET Standard 审查委员会[7]审查。该委员会由 .NET 平台实现者以及 .NET 社区的代表组成。其目标是只对我们能够真正在所有当前和未来的 .NET 平台中实现的 API 进行标准化。这些审查是必要的,因为 .NET 协议栈有不同的实现,有不同的限制。

我们预测到了这种类型的摩擦,这就是为什么我们很早就说过,.NET 标准将只对至少一个 .NET 实现中已经推出的 API 进行标准化。这乍一看似乎很合理,但随后你就会意识到,.NET Standard 不可能频繁地更新。所以,如果一个功能错过了某个特定的版本,你可能要等上几年才能使用,甚至可能要等更久,直到这个版本的 .NET Standard 得到广泛支持。

我们觉得对于某些特性来说,机会损失太大,所以我们做了一些不自然的行为,将还没有推出的 API 标准化(比如 AsyncEnumerable<T>)。对所有的功能都这样做实在是太昂贵了,这也是为什么有不少功能还是错过了 .NET Standard 2.1 这趟列车的原因(比如新的硬件特性)。

但如果有一个单一的代码库呢?如果这个代码库必须支持所有与 .NET 至今所实现功能有所不同的特性,比如同时支持及时编译(JIT)和超前编译(AOT)呢?

与其在事后才进行这些审查,不如从一开始就将所有这些方面作为功能设计的一部分。在这样的世界里,标准化的 API 集从构造上来说,就是通用的 API 集。当一个功能实现后,因为代码库是共享的,所以大家就已经可以使用了。

问题 2:.NET Standard 需要解码环

将 API 集与它的实现分离,不仅仅是减缓了 API 的可用性,这也意味着我们需要将 .NET Standard 版本映射到它们的实现上[3]。作为一个长期以来不得不向许多人解释这个表格的人,我已经意识到这个看似简单的想法是多么复杂。我们已经尽力让它变得更简单,但最终,这种复杂性是与生俱来的,因为 API 集和实现是独立发布的。

我们统一了 .NET 平台,在它们下面又增加了一个合成平台,代表了通用的 API 集。从很现实的意义上来说,这幅漫画是很到位的表达了这个痛点:

如果不能实现真正意义上的合并,我们就无法解决这个问题,这正是 .NET 5 所做的:它提供了一个统一的实现,各方都建立在相同的基础上,从而得到相同的 API 和版本号。

问题 3:.NET Standard 公开了特定平台 API

当我们设计 .NET Standard 时,为了避免过多地破坏库的生态系统,我们不得不做出让步[4]。也就是说,我们不得不包含一些 Windows 专用的 API(如文件系统 ACL、注册表、WMI 等)。今后,我们将避免在 net5.0net6.0 和未来的版本中加入特定平台的 API。然而,我们不可能预测未来。例如,我们最近为 Blazor WebAssembly 增加了一个新的 .NET 运行环境,在这个环境中,一些原本跨平台的 API(如线程或进程控制)无法在浏览器的沙箱中得到支持。

很多人抱怨说,这类 API 感觉就像“地雷”--代码编译时没有错误,因此看起来可以移植到任何平台上,但当运行在一个没有给定 API 实现的平台上时,就会出现运行时错误。

从 .NET 5 开始,我们将提供随 SDK 发布的默认开启的分析器和代码修复器。它包含平台兼容性分析器,可以检测无意中使用了目标平台并不支持的 API。这个功能取代了 Microsoft.DotNet.Analyzers.Compatibility NuGet 包。

让我们先来看看 Windows 特有的 API。

处理 Windows 特定 API

当你创建一个 Target 为 net5.0 为目标的项目时,你可以引用 Microsoft.Win32.Registry 包。但当你开始使用它时:

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");
}

你会得到以下警告:

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

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

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

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

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

  4. 抑制警告:当然,你可以通过 .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>

如果你正在构建一个 Blazor WebAssembly 应用程序,你不必这样做,因为 Microsoft.NET.Sdk.BlazorWebAssembly SDK 会自动做到这一点。

.NET 5 是 .NET Standard 和 .NET Core 的结合

.NET 5 及后续版本将是一个单一的代码库,支持桌面应用、移动应用、云服务、网站以及未来的任何 .NET 运行环境。

你可能会想“等等,这听起来很不错,但如果有人想创建一个全新的实现呢”。这也是可以的。但几乎没有人会从头开始一个新的实现。最有可能的是,它将是当前代码库(dotnet/runtime[8])的一个分支。例如,Tizen(三星智能家电平台)使用的是 .NET Core,只做了细小的改动,并在上面使用了三星特有的应用模型。

Fork 保留了合并关系,这使得维护者可以不断从 dotnet/runtime[8] 仓库中拉取新的变化,在不受其变化影响的领域受益于 BCL 创新,这和 Linux 发行版的工作方式非常相似。

当然,在某些情况下,人们可能希望创建一个非常不同的“种类”的 .NET,比如一个没有当前 BCL 的最小运行时。但这意味着它不能利用现有的 .NET 库生态系统,它也不会实现 .NET Standard。我们一般对这个方向的追求不感兴趣,但 .NET Standard 和 .NET Core 的结合并不妨碍这一点,也不会增加难度。

.NET 版本

作为一个库作者,你可能想知道 .NET 5 什么时候能得到广泛支持。今后,我们将在每年的 11 月发布 .NET 新版本,每隔一年发布一次长期支持(LTS)版本。

.NET 5 将在 2020 年 11 月正式发布,而 .NET 6 将在 2021 年 11 月作为 LTS 发布。我们创建了这个固定的时间表,使你更容易规划您的更新(如果你是应用程序开发人员),并预测对支持的 .NET 版本的需求(如果你是库开发人员)。

得益于 .NET Core 的并行安装(译注:一台机器可同时安装多个 .NET Core 版本,且向下兼容),它的新版本被采用速度相当快,其中 LTS 版本最受欢迎。事实上,.NET Core 3.1 是有史以来采用最快的 .NET 版本。

我们的期望是,每次发布(大版本)时,我们都会把所有框架名称连在一起发布。例如,它可能看起来像这样:

这意味着你心里可以有个预期,无论我们在 BCL 中做了什么创新,你都能在所有的应用模型中使用它,无论它们运行在哪个平台上。这也意味着,只要你运行最新版本的库,你总是可以在所有的应用模型消费最新的 net 框架带来的库。

这种模式消除了围绕 .NET Standard 版本的复杂性,因为每次我们发布时,你都可以假设所有的平台都会立即和完全支持新版本,而我们通过使用前缀命名惯例来巩固这一承诺。

.NET 的新版本可能会添加对其他平台的支持。例如,我们将通过 .NET 6 增加对 Android 和 iOS 的支持。相反,我们可能会停止支持那些不再相关的平台。这一点可以通过在 .NET 6 中不存在的 net5.0-someoldos 目标框架来说明。我们目前没有放弃一个平台支持的计划,那将是一个大问题,这不是预期的,若有我们会提前很久宣布。这也是我们对 .NET Standard 的模式,例如,没有新版本的 Windows Phone 实现了后面的 .NET Standard 版本。

为什么没有 WebAssembly 的 TFM

我们最初考虑为 WebAssembly 添加 TFM,如 net5.0-wasm。后来我们决定不这么做,原因如下:

  • WebAssembly 更像是一个指令集(如 x86 或 x64),而不是像一个操作系统,而且我们一般不提供不同架构之间有分歧的 API。

  • WebAssembly 在浏览器沙箱中的执行模型是一个关键的差异化,但我们决定只将其建模为运行时检查更有意义。类似于你对 Windows 和 Linux 的检查方式,你可以使用 OperatingSystem 类型。由于与指令集无关,所以该方法被称为 IsBrowser() 而不是 IsWebAssembly()

  • WebAssembly 有运行时标识符(RID)[9],称为 browserbrowser-wasm。它们允许包的作者在浏览器中针对 WebAssembly 部署不同的二进制文件。这对于需要事先编译成 WebAssembly 的本地代码特别有用。

如上所述,我们已经标记了在浏览器沙盒中不支持的 API,例如 System.Diagnostics.Process。如果你从浏览器应用内部使用这些 API,你会得到一个警告,告诉你这个 API 是不支持的。

总结

net5.0 是为能在任何平台运行的代码而设计的,它结合并取代了 netcoreappnetstandard 名称。我们还有针对特定平台的框架,比如 net5.0-windows(后面还有 net6.0-androidnet6.0-ios)。

由于标准和它的实现之间没有区别,你将能够比使用 .NET Standard 更快地利用新功能。而且由于命名惯例,你将能够很容易地知道谁可以使用一个给定的库--而无需查阅 .NET Standard 版本表。

虽然 .NET Standard 2.1 将是 .NET Standard 的最后一个版本,但 .NET 5 和所有未来的版本将继续支持.NET Standard 2.1 和更早的版本。你应该将 net5.0(以及未来的版本)视为未来共享代码的基础。

祝,编码愉快!


文中相关链接:

[1].https://github.com/dotnet/designs/blob/master/accepted/2020/net5/net5.md

[2].https://github.com/dotnet/standard/tree/master/docs/governance#process

[3].https://dotnet.microsoft.com/platform/dotnet-standard#versions

[4].https://github.com/dotnet/standard/blob/master/docs/faq.md#why-do-you-include-apis-that-dont-work-everywhere

[5].https://devblogs.microsoft.com/dotnet/introducing-net-standard/

[6].https://github.com/dotnet/standard/tree/master/docs/governance#process

[7].https://github.com/dotnet/standard/blob/master/docs/governance/board.md

[8].https://github.com/dotnet/runtime

[9].https://docs.microsoft.com/en-us/dotnet/core/rid-catalog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode538. 把二叉搜索树转换为累加树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

【BCVP升级】泛型主键的使用

&#xff08;图片来源于SqlSugar官网&#xff0c;5年5.0&#xff09;大家假期已经结束了吧&#xff0c;还有80天左右就要到2021年了&#xff0c;你准备好了么&#xff1f;BCVP&#xff08;Blog.Core&Vue Project&#xff09;项目已经开源2年多&#xff0c;从来没有停更过&a…

leetcode404. 左叶子之和(迭代和递归)

一:题目 二:上码 迭代 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right…

Dotnet Core使用特定的SDKRuntime版本

Dotnet Core的SDK版本总在升级&#xff0c;怎么使用一个特定的版本呢&#xff1f;假期过完了&#xff0c;心情还在。今天写个短的。一、前言写这个是因为昨天刷微软官方文档&#xff0c;发现global.json在 SDK 3.0 后&#xff0c;更新了一些内容。文档提到了这个更新&#xff0…

Spring中IOC的理解(通俗易懂版)

文章目录1.IOC提出背景2:IOC的核心概念3:IOC的实现方式4:IOC的入门案例(1):思路分析(2):代码解析5:DI入门案例(1):思路分析(2):代码解析6:DI依赖注入的方式(1):前言(2):Set方式注入(3):构造器注入(4):依赖的自动装配7:注解开发模式的依赖注入(1):前言介绍(2):注解模式的依赖注入…

首个使用Blazor 技术实现的社区软件 BlazorCommunity 发布

BlazorCommunity 是首个使用Blazor 实现的开源社区软件&#xff0c; 其组件基于Element-Blazor &#xff0c; Element-Blazor 是一个 API 模仿 Element&#xff0c;CSS 直接使用 Element 样式&#xff0c;HTML 结构直接使用 Element HTML 结构 的 Web开发库。由于基于了…

leetcode112. 路径总和

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

全球顶级开源大神们现身 COSCon'20

点击上方“开源社”关注我们| 作者&#xff1a;Will Wang| 编辑&#xff1a;沈于蓝| 责编&#xff1a;王皓月业界最具影响力的开源年度盛会2020中国开源年会 (COSCon20) 将于 10月24-25日由开源社举办。COSCon 以其独特定位及日益增加的影响力&#xff0c;吸引越来越多的顶级企…

做.NET开发多年,公司要我转Java...

10月13日&#xff0c;.NET5发布了(Release Candidate)RC2版本&#xff0c;包含语言新版本C#9和F#5等&#xff0c;这是正式版前的最后更新&#xff01;终于&#xff0c;万众期待的.NET5真的要来了&#xff01;公司让我转Java&#xff0c;我成功说服老板&#xff01;机会永远留给…

ASP.NET Core Blazor WebAssembly 之 .NET JavaScript互调

Blazor WebAssembly可以在浏览器上跑C#代码&#xff0c;但是很多时候显然还是需要跟JavaScript打交道。比如操作dom&#xff0c;当然跟angular、vue一样不提倡直接操作dom&#xff1b;比如浏览器的后退导航。反之JavaScript也有可能需要调用C#代码来实现一些功能&#xff0c;毕…

leetcode654. 最大二叉树

一:上码 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

浅议C#客户端和服务端通信的几种方法:Rest和GRPC和其他

本文来自&#xff1a;https://michaelscodingspot.com/rest-vs-grpc-for-asp-net/浅议C#客户端和服务端通信的几种方法&#xff1a;Rest和GRPC在C&#xff03;客户端和C&#xff03;服务器之间进行通信的方法有很多。一些功能强大&#xff0c;而其他功能则不是很多。有些非常快…

leetcode106. 从中序与后序遍历序列构造二叉树(java详解版)

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

COSCon’20开源教育论坛介绍

点击上方“开源社”关注我们| 作者&#xff1a;周添一| 编辑&#xff1a;沈于蓝| 设计&#xff1a;冯艺怡| 责编&#xff1a;王皓月论坛简介在当今数据驱动的智能社会&#xff0c;软件作为数字智能社会的数据基础设施&#xff0c;承载了社会的高效运转。在这个软件定义世界的潮…

leetcode105. 从前序与中序遍历序列构造二叉树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

想进BAT等大厂,到底要怎么做?

职场&认知洞察 丨 作者 / findyi这是findyi公众号的第82篇原创文章最近我的公众号多了很多学生读者&#xff0c;很多人问我&#xff1a;如果要进BAT等大厂&#xff0c;我是应该直接工作还是考研&#xff1f;对于未来要从事程序员行业的朋友来说&#xff0c;要不要考研&…

.NET 5.0 RC 2 发布,正式版将在 11 月 .NET Conf 大会上发布

原文&#xff1a;http://dwz.win/ThX作者&#xff1a;Richard翻译&#xff1a;精致码农-王亮说明&#xff1a;1. 本译文舍弃了少许我实在不知道如何翻译但又不是很重要的语句。2. 本文有不少超链接&#xff0c;由于微信公众号和头条平台外链会被剔除 URL 地址&#xff0c;所以原…

leetcode216. 组合总和 III

一:题目 二:上码 class Solution {/**递归深度根据k值确定,宽度的话那就[1,9]因为递归不允许重复&#xff0c;那么的话我们需要每次在横向遍历的起始位置1*/private List<List<Integer>> ans new ArrayList<>();private List<Integer> path new Arr…

BeetleX之Websocket协议分析详解

Websocket应用协议已经普及多年了&#xff0c;它是HTTP1.1的内部升级协议&#xff0c;主要作用是补充HTTP1.1无法灵活地主动推送消息给客户端的缺陷问题。在这里主要介绍一下使用组件如何扩展一个完整的Websocket协议。协议介绍Websocket并不复杂&#xff0c;但协议文档内容还是…

甲骨文是否可以要求 Java API 享有版权?这场10年官司怎么结

美国最高法院10月7日就 Oracle 甲骨文诉 Google 谷歌一案进行口头辩论。案件一直以来争议的核心是&#xff0c;甲骨文是否可以要求 Java API 享有版权&#xff0c;如果可以&#xff0c;那么谷歌是否侵犯了这些版权&#xff1f;Java API 是否可以享有版权&#xff1f;Sun 公司在…