[点晴永久免费OA].NET科普:.NET简史、.NET Standard以及C#和.NET Framework之间的关系
当前位置:点晴教程→点晴OA办公管理信息系统
→『 经验分享&问题答疑 』
最近在不少自媒体上看到有关.NET与C#的资讯与评价,感觉大家对.NET与C#还是不太了解,尤其是对2016年6月发布的跨平台.NET Core 1.0,更是知之甚少。在考虑一番之后,还是决定写点东西总结一下,也回顾一下.NET的发展历史。 首先,你没看错,.NET是跨平台的,可以在Windows、Linux和MacOS以及它们的各个发行版上运行,不仅如此,从2022年4月28日开始,.NET开源社区正式支持国产龙芯芯片龙架构(LoongArch),这使得.NET在国家信创这一领域又迈出了一大步。咦?.NET跨平台这事情我知道呀,为何要特别提起呢?因为真的有很多人不知道,而且不乏各种短视频平台里出现的各种技术专家和技术大咖,纷纷表示.NET只能在Windows上运行,跨平台困难,落地和部署困难。 其次,.NET的成功案例有很多,大家都知道,.NET和C#会用在游戏开发、工控领域、老系统维护等项目和场景中,却并不了解其实下面这些也都是.NET的成功案例,或者有着.NET的影子:
在上面的列表中,有些可能你还不认识,剩下的认识的大部分都是微软自己的产品,你会说.NET只有微软自己用,但不管是谁用,这些站点和应用都是超大规模级别的,说明使用.NET来构建超大规模级别的大型应用是完全没有问题的:容器化、云原生、微服务、Serverless,.NET都可以胜任;AI时代,ML.NET、Semantic Kernel、LLamaSharp、Cognitive Services等等.NET原生框架和开发SDK,在微软Azure OpenAI Services的加持下,为.NET在AI领域发力提供了更多的机会。 此外,.NET是开源的,.NET的各个部分通过不同的Repository维护在Github上,这些仓储基本上都是以MIT和Apache 2的许可协议进行开源,由微软员工作为主要贡献者,因此,在开源的同时,又保证了仓储的持续更新维护和提交代码的质量。不仅如此,.NET Foundation还收纳了不少知名开源项目,这对完善整个.NET生态起到了非常积极的作用。 那这里的.NET是指.NET Framework吗?算是,但也不完全是。之前为大家熟知的那个只能在Windows下运行的版本,称为.NET Framework,自2016年开始,微软发布跨平台版本的.NET框架时,它作为经典.NET Framework的跨平台版本,被称之为.NET Core,.NET Core延续到3.1版之后,被改名为.NET 5,然后就是后来的6、7、8、9等各个版本。对于这部分内容,我后面会介绍,但我想在介绍更多详细信息之前,先简单地回顾一下.NET的历史。 .NET极简史:从Visual J++开始大家都知道,刚刚退休的Java之父詹姆斯·高斯林曾经在1991年就开始参与Java语言的构建,然后Sun Microsystems公司于1996年发布了Java 1.0版本,但很少有人知道,微软在同年10月份发布了自己的Java语言:Visual J++。Visual J++开发的程序基于微软自研的MSJVM运行,虽然J++遵循Java语言规范,但微软并没有选择完全根据Sun公司的Java规范来设计自己的JVM,于是,MSJVM实际上并不完全支持Sun Java的所有能力,包括Java RMI和JNI。而另一方面,微软还在Visual J++中加入了一些自己的设计,比如通过回调函数和委托来实现事件处理,这就使得Visual J++变得更像另一种新的编程语言。不仅如此,Visual J++在访问系统资源方面,也不遵循Sun Java SDK规范,而是通过自己定义的J/Direct接口来让代码直接访问操作系统层面的API,于是,Visual J++在某些方面性能要大大优于Sun Java(很是怀疑这个J/Direct就是后来的P/Invoke)。从技术角度,使用了这些特殊功能的J++应用程序其实无法在Sun Java JVM上运行,不过当时也有不少开源项目,比如Kaffe项目,它们可以使J++应用程序无需移植即可直接在这些开源的JVM上运行。但这些开源项目也最终没有被广泛应用。 一开始的时候,Sun公司愿意在Java语言上与微软合作,而由于Visual J++里的各种骚功能和骚设计打破了Sun Java规范,以至于MSJVM未能通过Sun公司的合规性测试,于是,在Sun公司的起诉下,微软逐渐停止了Visual J++的研发。不过,在这个过程中,微软积累了丰富的技术和经验,这些技术和经验逐渐演化成后来的.NET平台和Visual J#(一种可以运行在.NET Framework上的Java编程语言,注意:是编程语言,就是用Java的语法写.NET Framework的应用程序)。Visual J#是Visual J++的续作,目的是能够让原来的Visual J++开发人员可以平滑地迁移到.NET平台上。 之后就是2002年4月15日发布的.NET Framework 1.0和Visual Studio.NET 2002(注意是Visual Studio.NET,不是Visual Studio,从Visual Studio 2005开始,名字里去掉了.NET字样),它可以安装并运行在Windows NT 4.0 SP6、Windows 98、Windows 98 SE、Windows ME、Windows 2000和Windows XP系统上。当年我正好读大三,记得数据库这门课的课程设计,就是用Visual Studio.NET 2002做的。由于操作系统可以是32或者64位的,属于不同的CPU架构,因此,从这个层面也可以说.NET是跨平台的:在Windows操作系统下跨平台。说起跨平台,虽然一开始由于市场策略、技术实现、开源生态等等因素,微软最终选择让.NET只在Windows下运行,但同时也力求将各种设计通过ISO和ECMA进行标准化,这为后续社区版跨平台.NET Framework:Mono Project、Xamarin以及.NET Core的出现,打下了坚实的基础。 值得一提的是,由于CLI标准化的存在,使得任何编程语言,只要符合相关规范,都可以在.NET上运行(这里我就不区分跨平台.NET还是经典.NET Framework了,单说编程语言这部分内容,两者原理是一样的),于是,你可能会看到有人使用以下语言来开发.NET应用程序:
从2002年4月15日到2022年8月9日这20年时间,.NET Framework经历了大大小小17个版本,功能也在不断的增强,在2016年随着.NET Standard的引入,从.NET Framework 4.5开始,不同版本的.NET Framework也被归属到对应版本的.NET Standard之下,而发布于2019年4月18日的.NET Framework 4.8,也成为了经典.NET Framework的最后一个版本(虽然2022年8月9日发布了.NET Framework 4.8.1,但并不是一个主版本)。 后续版本的.NET被称为.NET 5,从版本号上可以看到,.NET 5可以看成是.NET Framework 4.8的延续,它去掉了“Framework”字样,以示与之前经典.NET Framework的区别,.NET 5及后续版本都是跨平台的,现在回看这段历史可以发现,之前的.NET Core 1.0到3.1其实都是.NET跨平台历程的中间版本,这些版本存在的价值,就是让.NET开发人员和用.NET Framework开发的项目可以通过这些.NET Core的版本,能够无缝地、逐步地过渡到跨平台的、现代化的.NET上。不得不佩服微软在.NET跨平台这方面无论在市场战略上,还是技术战术上,都表现得非常出色。 .NET历史就介绍这么点,了解这些基本也就够了,接下来我会逐步从技术角度,来介绍一些与.NET相关的新概念。 .NET跨平台与.NET Standard可以这样理解:.NET Standard是.NET跨平台的基础。.NET Standard其实就是一套.NET下的API规范,它的第一个版本与2016年的.NET Core 1.0同时发布,每一个版本的.NET Standard都规定了实现这一版本规范的不同的.NET实现应该包含哪些API。更具体些:为了跨Linux、MacOS、Windows、iOS、Android等多个平台,.NET会针对这些平台提供不同的实现,这些实现包括:.NET Core、.NET Framework、Xamarin套件(iOS、Mac和Andriod)、用于游戏开发的Unity下的.NET等等,如果这些实现能够遵循某个版本的API标准,那么,基于这个版本的API标准所开发的应用程序,就可以运行于这些不同平台上,而这套API标准就是.NET Standard。另一方面,如果希望开发出来的类库和组件能够被不同平台的应用程序使用,那么,只需要指定这个类库和组件所基于的.NET Standard版本即可。 然而,最开始的.NET Framework并不能跨平台,微软为了逐步实现.NET跨平台这个目标,先后发布了从1.0到2.1一共9个版本的.NET Standard,每个.NET Standard版本下,都增加一部分.NET API的支持,比如,.NET Standard 1.0仅支持37118个API中的7949个,.NET Standard 2.0支持37118个API中的32638个,而最新的.NET Standard 2.1则支持所有37118个API。因此,在不同版本的.NET Standard下,就会有对应版本的.NET实现对其进行支持。比如对于.NET Standard 2.0,经典的.NET Framework需要4.6.1及以上的版本才支持.NET Standard 2.0,因为这些版本实现了.NET Standard 2.0中所定义的那32638个API。于是,使用.NET Standard 2.0开发的类库,就可以被.NET Framework 4.6.1所引用。 演练:在不同的.NET项目中使用.NET Standard 2.0类库在Visual Studio 2022中,新建一个.NET Standard 2.0的Class Library: 然后加入一个类: 再新建一个经典.NET Framework 4.6.1的Console Application: 然后直接引用前面的 当然,这个 打开这个ClassLibraryNetStandard20项目的输出目录,可以看到,编译出来的程序集被放在了 但是,如果我们新建一个.NET Standard 2.1的Class Library,则无法被.NET Framework 4.6.1的项目引用,此时会报错: 因为.NET Framework 4.6.1没有实现.NET Standard 2.1,换句话说,.NET Standard 2.1中的有些API在.NET Framework 4.6.1中并没有实现,那么基于.NET Standard 2.1开发出来的类库自然也不能被.NET Framework 4.6.1的项目所引用。经典.NET Framework的最后一个版本4.8.1仅实现了.NET Standard 2.0,因此,如果你打算开发一个既可以被经典.NET Framework项目使用,又可以被跨平台.NET(曾经的.NET Core,现在的.NET 5+)项目使用的话,你需要将你的类库定向(targeting)到.NET Standard 2.0,或者使用多目标框架(Multi-targeting)。 在【这个页面】中,有一张表,展示了.NET Standard各个版本与不同的.NET实现的版本之间的对应关系,可以通过下拉框来选择不同的.NET Standard版本来查看不同的.NET实现的哪些版本与之对应。理论如此,但是在真正实践的过程中,有些具体的问题是需要特殊处理的。比如:.NET Framework 4.7是支持.NET Standard 2.0的,但是,.NET Framework 4.7发布于2017年4月,而.NET Standard 2.0则晚于.NET Framework 4.7发布(2017年8月),那么如何让一个已经发布的.NET Framework版本支持新的.NET Standard呢?解决方案就是使用NuGet Package,将.NET Framework中未实现的.NET Standard API以NuGet Package的形式引入,从而弥补这个差异。因此你会发现,对于.NET Framework 4.7.1及其以前版本的.NET项目,如果需要引用一个由.NET Standard 2.0实现的类库的话,就需要额外引用
在编译出来的结果上也存在差异,下面左图是一个.NET Framework 4.7的项目引用了一个.NET Standard 2.0的项目后的编译输出,右图是.NET Framework 4.8.1的项目引用了.NET Standard 2.0项目后的编译输出,可以看到,4.7的项目编译后,会在编译路径下生成一堆System DLL,外加一个 多目标框架(Multi-targeting)尽管.NET Standard提供了不同.NET实现(.NET Framework、.NET Core和Xamarin等)之间统一的API规范,但在有些场景下,仍然希望能够充分利用不同平台的特性和性能优化,或者需要支持特定平台的功能,此时仅将项目定向到.NET Standard已经不能满足需求。对于这种场景,.NET允许开发面向多目标框架的类库,一方面可以通过条件编译指令来使用特定平台的API,另一方面也可以为类库的调用方提供不同平台的支持。 比如,在C#项目文件(.csproj文件)中,使用下面的方式,让类库同时支持.NET Standard 2.1项目和.NET Framework 4.8的项目:
注意上面的TargetFrameworks标记,在这个XML标记下,列出了该类库所支持的.NET Standard/.NET Framework的版本,它在编译之后,会产生两个输出文件夹,其中包含了支持不同版本.NET的程序集: 另一个需要注意的地方是,在上面的csproj文件定义中,指定了所使用的C#版本为8.0,这是因为“可空引用类型”(Nullable Reference Types)是在C# 8.0中引入的,而如果将代码同时定向到.NET Framework 4.8,那么就无法支持可空引用类型,因为.NET Framework 4.8所支持的最高的C#版本为C# 7.3。有关.NET与C#版本之间的关系,后文我会介绍。 一个使用“多目标框架”的非常著名的开源框架就是log4net。log4net是一个古老的.NET下的日志输出工具,它一开始是log4j的.NET移植版本,所以,老版本的log4net使用了很多经典.NET Framework特有的API,比如System.Configuration命名空间下的基于XML的框架配置代码。随着.NET Core和跨平台.NET的发布,log4net也逐步提供了对.NET Standard 1.3和.NET Standard 2.0的支持,所以,现在的.NET 5/6/7/8项目都可以直接引用log4net用作日志输出。在log4net的官方代码库中,可以学习到它是如何实现多目标框架的。 事实上从.NET 5开始,.NET真正实现了跨平台,.NET Standard也基本完成了它的使命,但.NET Standard并不会退出历史舞台,微软会继续对其进行维护。 至此,与.NET跨平台和.NET Standard相关的内容就差不多介绍完了,当然还有部分细节和一些历史遗留问题的处理方式相关内容(比如Portable Class Library,PCLs),这里就不再赘述了,否则篇幅太长,hold不住啊。接下来我们聊聊C#和.NET Framework之间的关系吧。 C#语言特性与.NET Framework如果你是C#语言的初学者,那么你一定会产生一个疑问: 由此可以得出一个结论:C#的语言特性是需要.NET Framework(或者.NET)支持的(有些高级的语言特性甚至需要不同版本的.NET CLR支持),但两者的版本之间也不一定需要有严格的对应关系。C#语言特性本质上是通过C#编译器实现的,只要编译输出的MSIL代码能够在.NET Framework(或者.NET)上运行起来,那么这些语言特性就可以被该版本的.NET Framework所支持。下面请看一个具体的案例。 演练:在.NET Framework 4.6.1的项目中使用C# 9.0的新特性现在我们尝试在一个.NET Framework 4.6.1(发布于2015年11月)的项目中,使用C# 9.0(发布于2020年11月)的新特性。首先新建一个.NET Framework 4.6.1的Console Application: 然后,修改csproj文件,将C#语言版本升级到C# 9.0: 然后,使用C# 9.0中“关系型模式匹配”新特性编写一段代码: 然后直接运行,可以看到,程序是可以正常编译执行的: 那么,是不是所有的C# 9.0的新特性,都可以在.NET Framework 4.6.1中使用呢?答案是否定的,就要看C# 9.0的编译器是否可以生成能够被该版本.NET Framework所支持的代码,或者说,C#编译器所生成的代码中依赖的那些类型,是否在该版本的.NET Framework下支持。举个例子,同样是C# 9.0的新特性,仅限Init的资源库新特性则无法直接在一个.NET Framework 4.6.1的项目中使用,编译器提示: 原因是,C# 9.0编译器在编译带有这个新语法特性的代码时,需要检查.NET下是否包含 请注意:经典.NET Framework最高支持到C# 7.3,C# 8.0是专门面向.NET Core的第一个主要C#版本,它的一些新功能依赖于新的Core CLR的相关功能。【这篇官方文档】详细列举了C#语言的发展历史以及各个版本的新功能,下面这张表格列举了不同.NET版本下,创建新项目时所使用的默认的C#语言版本(参考官方文档): 转自https://www.cnblogs.com/daxnet/p/18299758 作者dax.net 该文章在 2024/7/19 17:29:00 编辑过 |
关键字查询
相关文章
正在查询... |