日志

为什么.NET Standard 仍然有意义?

 来源    2021-01-14    1  

.NET Standard 是.NET 官方的API规范,可在许多.NET环境中使用。之所以存在,面向.NET Standard 2.0的库提供了最大可能的覆盖范围,并启用了几乎所有现代的.NET功能,例如C#9,IAsyncEnumerable等,因此所有库都应针对该平台。

.NET标准背后的动机是在.NET生态系统中建立更大的一致性。

背景介绍

.NET Framework 很早并且没有跨平台,.NET Framework发行后,.NET的几种实现(例如 Mono 和 Unity) 出现在其他平台上,微软还发布了许多其他实现,例如 UWP, Silverlight和最新的.NET Core, Microsoft重命名为.NET 5的.NET Core是最重要的,因为它是Microsoft真正的.NET跨平台实现,并且Microsoft打算维护该平台。

Microsoft引入了可移植类库(PCL), 并最终引入了 .NET Standard,以便不同的实现可以共享一组通用的API,这意味着.NET代码在各个平台之间都是兼容的,并且您可以在任何实现中使用编译后的代码。根据Microsoft的说法,.NET Core,.NET 5,.NET Framework,Mono,Xamarin.iOS,Xamarin.Mac,Xamarin.Android,Universal Windows Platform和Unity都以某种方式支持.NET Standard。但是,.NET 5尚未运行所有这些平台。

将来,我们应该会看到.NET 5 正在支持更多的平台,因为Microsoft正在“积极开发”用于iOS和Android等平台的.NET(.NET 5+)。所以:.NET5 是具有统一功能和API的单一产品。

但是,目前,.NET Standard 是兼容大多数.NET 环境的唯一目标,如果要构建在所有这些平台上运行的库,则需要以.NET Standard 2.0为目标,这是实现的表格以及它们支持的.NET Standard版本

支持.NET Standard 2.0和.NET 5

您可以在.NET Standard 2.0中使用最新的.NET特性,比如 C#9,IAsyncEnumerable ,Span,System.Text.Json等,这样的意义在于,这样做的好处是巨大的,在.NET Framework的项目上也可以使用这些功能。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
    <LangVersion>9</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
    <PackageReference Include="System.Linq.Async" Version="5.0.0" />
    <PackageReference Include="System.Memory" Version="4.5.4" />
    <PackageReference Include="System.Text.Json" Version="5.0.0" />
  </ItemGroup>

</Project>

下边是这个库的一些代码,它同时支持了.NET Standard 2.0 和.NET 5,但是在一个 .NET Framework的运行项目上使用了这个库,.NET的新特性仍然可以使用。

using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

namespace DotNetStandardLibrary
{
    public class ExampleClass
    {
        public string Test { get; }

        public ExampleClass(string test)
        {
            Test = test;
        }

        /// <summary>
        /// Uses the Span type
        /// </summary>
        public ExampleClass WriteSpans()
        {
            var spans = new Span<string>(new string[] { "One", "Two" });
            foreach (var span in spans)
            {
                Console.WriteLine(span);
            }

            return this;
        }

        /// <summary>
        /// Use an Async foreach with IAsyncEnumerable
        /// </summary>
        public static async Task DoAsyncNumbersAsync()
        {
            var asyncEnumerable = AsyncEnumerable.Range(0, 10);
            await foreach (var number in asyncEnumerable)
            {
                Console.WriteLine($"Awaited Number: {number}");
            }
        }

        /// <summary>
        /// Serialize and Deserialize with System.Text.Json
        /// </summary>
        public ExampleClass DoSerialize()
        {
            var dailyTemperature = new DailyTemperature(10, 20);
            var json = JsonSerializer.Serialize(dailyTemperature);
            dailyTemperature = JsonSerializer.Deserialize<DailyTemperature>(json);

            if (dailyTemperature == null)
            {
                throw new InvalidOperationException();
            }

            Console.WriteLine($"Json: {json}\r\nHigh: {dailyTemperature.HighTemp} Low: {dailyTemperature.LowTemp}");

            return this;
        }

    }

    public static class Extensions
    {
        /// <summary>
        /// C# Pattern matching example
        /// </summary>
        public static bool IsLetter(this char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
    }

    /// <summary>
    /// IAsyncDisposable Example
    /// </summary>
    public class AsyncDisposable : IAsyncDisposable
    {
        public ValueTask DisposeAsync() => new ValueTask(Task.FromResult(true));
    }

    /// <summary>
    /// Record example
    /// </summary>
    public record DailyTemperature(double HighTemp, double LowTemp);
}

在.NET Framework 是这样使用的

using DotNetStandardLibrary;
using System;
using System.Threading.Tasks;

namespace DotNet461ConsoleApp
{
    internal class Program
    {
        private static async Task Main()
        {
            var asyncDisposable = new AsyncDisposable();
            await asyncDisposable.DisposeAsync();

            _ = new ExampleClass("test").WriteSpans().DoSerialize();

            await ExampleClass.DoAsyncNumbersAsync();

            Console.WriteLine($"The character 7 {('7'.IsLetter() ? "is" : "is not")} a letter");
        }
    }
}

总结

.NET Standard可能会部分冗余,但.NET 5目前还不能替代.NET Standard, .NET 5提供了很多新特性,但是,像Unity和Mono这样的运行时仍然存在,并且在很多地方使用,他们可能会选择继续使用它们,而且,.NET Framework上仍然有成千上万的旧代码库,如果目标是.NET Standard 2.0,则保证这些代码库可以使用您的库, 所以.NET Standard还会存在一段时间,并且目前的范围最广。

原文作者: Christian Findlay
原文链接:https://christianfindlay.com/2020/12/21/net-standard/

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

相关文章
如何找到有意义的单词来表示从word2vec向量派生的每个k-means集群?
问答我使用Python中的gensim包加载预先训练的Google word2vec数据集.然后,我想使用k-means在我的单词向量上找到有意义的聚类,并找到每个聚类的代表性单词.我正在考虑使用其对应的 ...
1
c# – 将超过96个.Net Standard 2程序集复制到Console(.Net framework)应用程序的bin文件夹中
问答在vs 2017.3预览版3中,我创建了一个包含三个项目的解决方案:Netstandard2库(.Net Standard v2.0预览版),控制台应用程序A(.Net框架)和控制台应用程序B(.Ne ...
1
java – 通过改变每个迭代的每个字母将一个单词转换成另一个单词的算法,这个单词应该形成另一个有意义的单词?
问答我想制作一个将一个单词改为另一个单词的算法.例如,给定的单词是"MUD",我需要将其转换为"BED".对于每次迭代,我可以更改一个字符,但这应该形成另一个有意义 ...
1
模型 – 视图 – 控制器 – MVC或MVP?哪种设计模式最有意义?
问答你们更喜欢哪个?我一直在研究两者,人们称之为肯定存在一些不一致的地方. 我会尝试记下差异是什么,如果我错了你可以纠正我. MVC >模型保存对它自己的观察者(视图)的引用,对模型的更新通知观察者 ...
5
c# – 在库和.Net framework 4.6.1中使用.Net Standard 1.4和应用程序时,无法加载文件System.IO.FileSystem,Version = 4.0.1.0
问答我有一个包含库和2个应用程序的解决方案.这些应用程序代表相同的程序,其中一个程序是通过UAP10定位到Windows App Store,另一个是使用.Net Framework 4.6.1定位到Mi ...
2
c# – 如何创建一个同时针对.NET 2.0和.NET Standard的库?
问答我有一个目前支持.NET 2.0的small library. 我不使用后来框架版本的任何功能,所以保持2.0支持会很好,但我也希望以.NET Core(或更确切地说,.NET标准)为目标. 我试图将 ...
3
visual-studio-2017 – .NET Standard项目的代码覆盖率
问答如何获取使用Visual Studio 2017创建的.NET Standard项目的代码覆盖率结果? >我尝试使用Visual Studio附带的功能(菜单→测试→分析代码覆盖率→所有测试). ...
2
Java中的闭包模拟是否有意义?
问答具有闭包的语言(例如Ruby)使得优雅的构造能够转换列表.假设我们有一个班级 class QueryTerm { String value; public String getValue() {... ...
1
C 11原子:将它们与内存映射I / O一起使用是否有意义,甚至可能?
问答据我所知,C volatile和可选的内存asm for memory fence已用于在内存映射I / O之上实现设备驱动程序.在Linux内核中可以找到几个例子. 如果我们忘记未捕获的异常(如果有 ...
1
`exit $?`与bash中的`exit`有意义不同?
问答我的理解是,在bash中,普通出口将完成一个脚本,其中包含最后一个命令的退出状态.但我也看到人们使用退出$?当我提出它具有相同的行为时被质疑. 这两个脚本之间有什么有意义的区别吗? #!/bin/ba ...
1
c – 在可移动和不可复制的类上使用移动和交换习语是否有意义
问答如果我有一个类如 class Foo{ public: Foo(){...} Foo(Foo && rhs){...} operator=(Foo rhs){ swap(*this, ...
3
android – AlertDialog.Builder类有什么意义?
问答在Android中,每个对话框都使用Builder显示该对话框类. Builder是这些类中的静态内部类.那么为什么Builder可以控制构建对话框呢?提前致谢.::它只是一个帮助类,它允许您调用链中 ...
1
php – 在析构函数中归零私有变量有什么意义?
问答我在我正在使用的代码中发现了以下模式:在析构函数的某些类中,我发现私有变量是空的,例如: public function __destruct() { foreach($this->observ ...
2
github-pages – 在GitHub页面中使用robots.txt有什么意义?
问答我知道robots.txt文件用于阻止第三方索引内容网站的网页爬虫. 但是,如果此文件的目标是划分站点的私有区域或保护私有区域,这是尝试使用robots.txt隐藏内容的意义,如果所有都可以在GitH ...
2
c – 在动态内存上运行,重载const memeber函数是否有意义?
问答来自C Primer 5 Edition的练习使我陷入困境,这就像 Exercise 12.3: Does this class need const versions of push_back an ...
1
有 #!在网址中组合有特殊意义吗?
问答我现在已经看到一些网址在网址中使用了这种符号组合:#! 例如:facebook: http://www.facebook.com/home.php?#!/?sk=messages 或推特: http: ...
2
对象的监视器在java中的意义是什么?为什么要使用这个词?
问答当阅读关于java线程的文章时,我经常注意到以下表达式:"当前线程是此对象的监视器的所有者.我抓住的含义:线程获得对对象操作的权利.但我很困惑为什么使用短语"对象的监视器" ...
2
sharepoint – 如何检查是否安装了MOSS Standard或MOSS Enterprise?
问答如何检查是否安装了MOSS Standard或MOSS Enterprise?::这个链接应该排除你- Determining sharepoint versions 编辑:文章现已消失,所以请看下面 ...
1
active-directory – 在哪里可以找到LDAP Active Directory消息的列表,并有意义?
问答我收到错误: LDAPException: Invalid Credentials (49) Invalid Credentials LDAPException: Server Message: 80 ...
2
c – 将所有内容放在QApplication的子类中是否有意义?
问答在我的基于插件的体系结构中,插件必须能够访问应用程序的所有核心组件,例如主窗口,settingswidget,设置,托盘图标和几个全局不可变变量. 由于应用程序是一个全局单例,因此可以直接将其子类化并 ...
2