.NET000-关于.NET平台及技术栈

.NET现状

目前.NET的应用主要集中在工业领域(国内),在互联网时代因为各种各样的原因,国内大厂大部分技术栈选择的都是Java相关的,但在未来十年内笔者更加看好.NET和Golang在云技术、数字化转型等方向的发展情景,国内字节全面拥抱Go,.NET国内环境较差,但笔者最喜欢的一门编程语言。

.NET可以做什么?

从桌面开发(在Windows端和工控领域占据了很重的比例)、Web(国内大厂大多用Java)、Cloud(当前和未来十年.NET和Go具有很大的优势)、Mobile(Xamarin很优秀但是坑太多,MAUI不知道何时才能真正成长起来,很期待)、GAMING(Unity在游戏领域可谓是大放异彩)、LoT、AI等。笔者看好的方向是数字换转型、游戏、元宇宙、办公自动化、云等方向。

关于最新.NET平台的动态

目前是2021年11月15日,微软.NET6(LTS版本)和Visual Studio2022CR版本已发布。列举一些重要的新增功能:

  • 性能改进:FileStream、PGO、Crossgen2
  • 热重载,可用于修改应用的源代码,并立即将这些更改应用到正在运行的应用。该功能的目的是避免在编辑之间重启应用,从而提高工作效率。Visual Studio2022提供了热重载的功能dotnet watch。(关于热重载之前取消支持被喷惨了,哈哈哈)
  • .NET MAUI:一套代码,多端编译,目前仍处于预览状态。
  • C#10和模板:async main()、Top-level statements、Target-typed new expressions、Implicit global using directives、File-scoped namespaces、Nullablereferencetypes。
  • SDK工作负载:为了减小 .NET SDK的大小,某些组件已放置在新的可选SDK工作负荷中。这些组件包括.NET MAUI和Blazor WebAssembly AOT。如果使用Visual Studio,它将负责安装所需的任何SDK工作负载。如果使用.NET CLI,可以使用新命令管理 dotnet workload工作负荷。
  • ASP.NET Core:ASP.NET Core包括针对Blazor WebAssembly应用和单页(AOT)编译的最少API、提前执行AOT编译的改进。此外,Blazor组件现在可以从JavaScript呈现并集成到现有的基于JavaScript的应用。
  • 安全性:.NET6添加了对两个关键安全缓解措施的预览支持:控制流强制技术 (CET) 和"写入独占执行" (W^X) 。CET是一种 Intel 技术,在某些较新的Intel和AMD处理器中可用。它将功能添加到硬件,防止某些控制流劫持攻击。.NET6为x64 Windows CET提供支持,必须显式启用它。W^X 适用于.NET 6的所有操作系统,但仅在Apple Silicon上默认启用。W^X 通过禁止内存页同时可写入和可执行来阻止最简单的攻击路径。
  • NuGet包验证:新的包验证工具可用于验证包是否一致且格式良好
  • 反射API:.NET 6 引入了以下新 API,用于检查代码并提供可为null性的信息:System.Reflection.NullabilityInfo、
    System.Reflection.NullabilityInfoContext、System.Reflection.NullabilityState。这些 API 可用于基于反射的工具和序列化程序。
  • 新的LINQ API:https://docs.microsoft.com/zh-cn/dotnet/core/whats-new/dotnet-6

关于C#8-C#10 好用的新语法

C#9.0是.NET5,C#10.0是.NET6

Top-Level Statements(.NET5)

  • *语句规定了无需类,无需命名空间,无需Main入口方法,直接一句话即可。
  • 同一个项目中只能由一个文件具有*语句,*语句中可以直接使用await语法,也可以声明函数和内部类。
Console.Write("Hello world!");

这样的优势在于当你不安装IDE的时候,直接dotnet new console -n AlbertTestSynctax创建一个控制台项目,echo Console.WriteLine("Hello world) > Program.cs,dotnet run *.csproj。非常便捷。

Implicit global using directives(.NET6)

全局USING指令,只要有一处用到了就可以应用到整个项目,而无需重复using。在.NET6项目中*.csproj项目会默认开启ImplicitUsings为enable,全局隐式使用Using,开启后编译器会自动隐式添加对于System、System.LINQ等常用命名空间的引入。项目文件结构为:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
	<!--隐式Using ImplicitUsings-->
    <ImplicitUsings>enable</ImplicitUsings>	 
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\_211112_Demo01_DataBaseRelation\_211112_Demo01_DataBaseRelation.csproj" />	
  </ItemGroup>

  <ItemGroup>
	<Using Include="_211112_Demo01_DataBaseRelation" />
  </ItemGroup>

</Project>

有两种方式来实现全局隐式使用,第一种在using前面加上global,第二种在项目文件中添加Using Inclue标签,笔者喜欢采用第二种方式。例如上面代码片段中的

Using资源管理的问题(C#8.0)

这个Using和上面的USING不一样,这边是用于释放非托管资源的using,在C#中非托管资源在创建的时候需要包裹在using()中,以便在非托管资源使用完毕后进行资源的回收,调用Dispose()方法。之前的写法在嵌套的时候,会造成大括号过多的情况,例如:

using(var conn = new SqlConnection("xxx")){
    conn.Open()
    using(var cmd = conn.CreateCommand){
        xxx;
    }
}

新语法,可以直接using而无需添加(),当代码执行离开变量作用域时,对象资源就会被释放,不过使用的时候一定要注意作用域的问题,不然会入坑。思考一下这里为什么要用{}来括起来,不括起来会有什么影响?

//注意USING资源管理陷阱
{
    using var fs = File.OpenWrite("D:/1.txt");
    using var ws = new StreamWriter(fs);
    ws.WriteLine("Albert is very elegant.");
}
string s = File.ReadAllText("D:/1.txt");
Console.WriteLine(s);

File-Scoped Namespaces(.NET6)

文件范围的命名空间声明,朴实无华去大括号,无需将类包含在名称空间的大括号中了,例如:

namespace albert;
internal class Student{
    Console.WriteLine("xxx");
}

Nullable Reference Types(C#8.0)

可空引用类型,此种类型可以提高代码的健壮程度,C#目前有值类型,可空值类型、引用类型、可空引用类型。在.NET6中默认开启可空引用类型检查enable,对于引用类型没有添加?来修饰,如果编译器发现存在这个变量赋值null的可能性的时候,编译器会给出警告信息。

Record Types(.NET5)

之前C#中运算符默认是判断两个变量指向的是否是同一个对象(引用的地址),即使两个对象内容完全一样吗,也不相等。当然我们可以通过重写Equals方法、重写运算符等来解决这个问题,不过需要开发人员编写非常多的额外代码,在.NET5中增加了Record类型,编译器会自动为我们生成Equals、GetHashCode等方法。Record(string A,string B)会默认生成一个构造函数,将A和B的get设置为init,这样只能通过构造函数赋值,函数内部和外部皆无法赋值。

public record Person(string FirstName,string LastName){
    public int Age {get;set;}
    public Person(int age):this(FirstName,LastName){
        this.Age = age;
    }
}

Person personA = new Person("zao","zao");
Person personB = new Person("zao","zao");
Console.WriteLine(Object.ReferenceEquals(personA,personB));//False
Console.WriteLine(personA); //会打印出所有属性的信息
Console.WriteLine(personA==personB);//True

//小知识,C#进行副本拷贝,而不是引用拷贝
Person personC = personA;//此为引用拷贝,两者指向同一块内存。
Person personD = personA with {};//此为副本拷贝,不同的内存。
上一篇:Java:内部类(静态内部类、成员内部类、局部内部类、匿名内部类)


下一篇:kmp字符串匹配