重磅发布 | 更快、更强的 .NET 7

发布于:2022-11-09 ⋅ 阅读:(9) ⋅ 点赞:(0) ⋅ 评论:(0)

.NET Conf 2022在11⽉8⽇11点正式开始了,为期三天的会议(11⽉8-10⽇),围绕 .NET 7 展开。相信各位⼩伙伴都已经开始安装 .NET 7 正式版本以及相关的开发⼯具。这次 .NET 7 围绕传统的 C#,ASP.NET Core, Blazor, .NET MAUI, 云原⽣等内容进行了更新。下面归类总结⼀下我比较关心的更新内容,希望能给各位⼩伙伴⼀个快速的介绍。

C# 11 新增的六大功能

1. 泛型属性 - Generic attributes

泛型是编程语⾔的一种风格。让程序员在强类型程序设计语⾔中编写代码使⽤⼀些以后才指定的类型。C# 在2.0 开始⽀持泛型,C# 版本更替时不断对泛型的⽀持进⾏了增强和补充。在 C# 11 中,增加了泛型属性。

这是⼀段 ASP.NET 的代码,每个字段都有⼀些要求属性,如必填的字段,限制范围,以及对应的类型等。

public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; } = null!;
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; } = null!;
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}

你可以通过 System.Attribute 派⽣出不同的属性。

在 C# 11 之前你也可以去做泛型属性的定义,通过 System.Type 在⾃定义属性类中作为构造函数的参数进⾏传递。

[AttributeUsage(AttributeTargets.Class)]
public class Conditions: Attribute
{
public Conditions(Type t)
{
ParamType = t;
}
public Type ParamType { get; }
}

实现

[Conditions(typeof(string))]
public class Player
{
public string Number { get; set; }
public string Name { get; set; }
}

⽽ C# 11 增加了对泛型属性的支持。直接定义⼀个泛型类,不⽤再将 System.Type 作为参数传递给构造函数。而且可以有⼀个或者多个类型作为参数, ⽽且类型安全性也增加了。

[AttributeUsage(AttributeTargets.Class)]
public class Conditions<T>: Attribute
where T : class
{
public Conditions()
{
}
public T ParamType { get; }
}
[Conditions<string>()]
public class Player
{
public string Number { get; set; }
public string Name { get; set; }
}

因为有了泛型类的加持,您可以在类型参数上灵活添加不同的条件约束。

2. 原始字符串 - New Raw string literals

在定义字符串时,我们往往夹杂着很多的符号,换⾏还有空格,但过往这些都需要增加转移字符,但现在通过原始字符串可以让字符串定义更为简单,也更容易给⼈接受。

string longMessage = """
   This is a long message.
   It has several lines.
        Some are indented
                 more than others.
   Some should start at the first column.
   Some have "quoted text" in them.
   """;

3. 列表模式 - List patterns

从 C# 11 开始,可以将数组或列表与模式的序列进⾏匹配,如以下示例所示: 

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True

这个虽然看似是语法糖,但是对于⼀些数据处理的场景时⾮常有⽤的,例如 CSV 或者事固定⻓度的⽂件数。

4. 字符串插值中的换⾏符 - Newlines in string interpolations

以前,字符串插值 {text} 的⽂本只允许⼀⾏。现在在 C# 11 中,此⽂本可以允许多⾏。$ 特殊字符将字符串⽂本标识为内插字符串。内插字符串是可能包含内插表达式的字符串⽂本。将内插字符串解析为结果字符串时,带有内插表达式的项会替换为表达式结果的字符串表示形式。

string message = $"The usage policy for {safetyScore} is {
    safetyScore switch
  {
    > 90 => "Unlimited usage",
    > 80 => "General usage, with daily safety check",
    > 70 => "Issues must be addressed within 1 week",
    > 50 => "Issues must be addressed within 1 day",
    _ => "Issues must be addressed before continued use",
  }
  }";

5. 改进方法组转换为委托 - Method Group conversion to Delegate

委托⽤于将⽅法作为参数传递给其他⽅法。最常见的委托是 Action、Func 和 EventHandler。您可以使⽤ lambda 表达式来提供委托,也可以使⽤⽅法组。您还可以将委托缓存到⼀个字段中,并在需要时重⽤该实例。

例如这个就是我们经常使⽤的定义:

void ActionDelegetDemo(Func<string> action) { }
string GetPlayer() => "";

在 C# 11 之前 我们通过方法组进行委托的调用,如:

ActionDelegetDemo(GetPlayer);
ActionDelegetDemo(new Func<string>(GetPlayer));

在 C# 11 后,你可以通过没有闭包的 Lamda/⽅法中去实现  

ActionDelegetDemo(() => GetPlayer());

也可以通过⼿动委托的⽅式来实现

static readonly Func<string> Instance = new Func<string>(GetPlayer);
ActionDelegetDemo(Instance);

6. 接口中的静态抽象成员 - Static Abstract Members in Interfaces

C# 11 和 .NET 7 包括接⼝中的静态抽象成员。它可定义重载运算符或其他静态成员的接⼝。使⽤静态成员定义接口后,可使⽤这些接⼝作为约束来创建使⽤运算符或其他静态⽅法的泛型类型。通过将 static 和 abstract 修饰符添加到不提供实现的任何静态成员,如:

public interface IGetNext<T> where T : IGetNext<T>
{
static abstract T operator ++(T other);
}

这个功能在泛型处理是⾮常⽅便的,我们可以在接⼝中包含静态抽象成员,然后我们可以对泛型⽅法指定⼀个约束,即类型参数应该从这个特定的接⼝派⽣。⼀旦完成,泛型⽅法就可以轻松调⽤静态⽅法。

Native AOT 来了

如果你是传统的 Xamarin 开发者,你肯定对 AOT 技术不陌生,因为有 Mono AOT,⽽针对客户端场景和服务器场景也有 ReadyToRun。Native AOT 技术可以将 .NET 应⽤程序编译成本机可执⾏⽂件,也还可以⽣成独⽴的动态或静态库从⽽给其他编程语⾔调⽤。Native AOT 应⽤程序启动速度⾮常快,⽽且对于内存的使⽤也是⾮常⼩的。你可以在没有 .NET 运⾏时的设备上直接运⾏ Native AOT 的应⽤。Native AOT 不使用 JIT 编译器,所以它可以在 JIT 受限制的环境中运⾏。它可以在 Arm64 / x64 的环境下运⾏。这个或者让⼤家想到了 Rust,也想到了 Go。现阶段,.NET 7 的 Native AOT ⾮常受限只有控制台和⼀些库文件⽀持。但这是第一步,希望各位⼩伙伴也能尽量去尝试。

如果你要创建⼀个 Native AOT 的应⽤,需要在 csproj ⽂件中添加:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

你也可以针对 Linux 或者 Windows arm/x64 编译 Native AOT 应⽤,例如

dotnet publish -r linux-arm64 -c Release

注意在 Ubuntu 环境下,你需要添加以下的⼀些库 clang zlib1g-dev

sudo apt-get install clang zlib1g-de

现在 Native AOT 还是⽐较受限,我更期待能⽀持⼀下 MAUI,这样是不是路更⼴。还有我使⽤ Native AOT 编译出来的应⽤过⼤,是否需要考虑压缩⼀下呢?我能理解它是增量的,但是⼀个 HelloWorld 应⽤也⼤得有点夸张了。希望它能越来越好。

端技术改进

.NET MAUI 是⼀道坎,或者很多⼩伙伴希望它能做更多。有⼈会希望性能有所提升,有⼈希望能在 Linux 上得到⽀持,也有⼈希望 IDE 能够完善⼀点。我⼀直和 .NET MAUI 的团队保持沟通,也希望尽快能实现各位⼩伙伴的愿望。在 .NET 7 中,.NET MAUI 在桌⾯应⽤的⽀持有了很多的改善。在⼿势,在桌⾯菜单,以及对⿏标⽀持,右键菜单,窗体缩放都有很好的⽀持。或者期望更多了。这不是最好的更新,但是这是更稳定的跨平台应⽤开发。我们在期待更⼤更新的时候,更应该开始着⼿投⼊到 .NET MAUI 的应⽤开发中来了。

 

开发体验上 .NET MAUI 已经⽀持 iOS 16 和 Android 13了,这也解决了 Xcode 14不兼容的问题。与时俱进是我喜欢 .NET MAUI 的原因。还有 Hot Reload 也有了⼀个进化,⽀持 .NET for iOS 和 .NET for Android 以及 Blazor WebAssembly 了。

说完 .NET MAUI , 说到端应⽤不能不提及 Blazor,这⼏年 Blazor 的应⽤持续攀升,这也得益于一个好的性能以及 WebAssembly 技术的发展。我个⼈很喜欢 WebAssembly。.NET 7 为基于 JavaScript 的应⽤中的 WebAssembly 上运⾏ .NET 提供了改进的支持,包括丰富的 JavaScript 互操作机制。.NET 7 中的 WebAssembly ⽀持是基于 Blazor WebAssembly 应⽤程序,但也可以独⽴于 Blazor 使⽤。现有的 JavaScript 应⽤程序可以使⽤ .NET 7 中扩展的 WebAssembly ⽀持来重⽤ JavaScript 中的 .NET 库或构建全新的基于 .NET 的应⽤。Blazor WebAssembly 应⽤程序还可以使⽤新的 JavaScript 互操作机制来优化与 JavaScript 和 Web 平台的交互。

各位⼩伙伴在安装好 .NET 7 后可以在命令⾏中通过 workload 添加 wasm 的⽀持:

dotnet workload install wasm-tools
dotnet workload install wasm-experimental

添加完成后,你就可以通过创建你的 wasm 应用:

dotnet new wasmbrowser

还有也有了 AOT 的⽀持,通过 AOT 你可以提升运⾏速度,通过修改 csproj ⽂件就可以获取 AOT ⽀持

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
               <TargetFramework>net7.0</TargetFramework>
               <WasmMainJSPath>main.js</WasmMainJSPath>
               <OutputType>Exe</OutputType>
               <Nullable>enable</Nullable>
               <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+                <PublishTrimmed>true</PublishTrimmed>
+                <TrimMode>full</TrimMode>
+                <RunAOTCompilation>true</RunAOTCompilation>
     </PropertyGroup>
</Project>

发布也⾮常简单

dotnet publish -c Release

⽽且还⽀持在本地托管发布应⽤

dotnet tool install --global dotnet-serve
dotnet serve --mime .wasm=application/wasm --mime .js=text/javascript --
mime .json=application/json --directory bin\Release\net7.0\browserwasm\
AppBundle\

ML.NET 2.0 发布

⽤ .NET 做机器学习,很多⼈会打⼀个问号。但微软就是要把 .NET 可以做机器学习的问号变成了叹号。ML.NET 在 1.5 后,特别是 ML.NET CLI 已经⾮常好⽤,特别是 AutoML 这块。在 ML.NET 2.0 对于⾃然语⾔这块的处理都有⾮常⼤的改进。这得益于 TorchSharp 的改进,或者是受TensorFlow.NET 的影响,⾃家⽀持的 TorchSharp 也有了很⼤的进步。

⾃然语⾔是⾮常常⻅的问题,ML.NET 新增加了⽂本分类的 API,让开发者通过少量的代码就可以完成⽂本分类,情感分析以及摘要提取等⼯作。具体的 API 封装如下:

你可以理解为 ML.NET 帮你完成了 80% 的⼯作,包括最复杂的⾃然语⾔算法构建等⼯作,你需要做的就是提供数据, 和相关 API 的调⽤。这是官⽅的⼀个示例

using Microsoft.ML;
using Microsoft.ML.TorchSharp;
var mlContext = new MLContext();
var reviews = new[]
{
new {Text = "This is a bad steak", Sentiment = "Negative"},
new {Text = "I really like this restaurant", Sentiment = "Positive"}
};
var reviewsDV = mlContext.Data.LoadFromEnumerable(reviews);
var pipeline =
mlContext.Transforms.Conversion.MapValueToKey("Label",
"Sentiment")
.Append(mlContext.MulticlassClassification.Trainers.TextClassification(num
berOfClasses: 2, sentence1ColumnName: "Text"))
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
// Train the model
var model = pipeline.Fit(reviewsDV);

我们可以看到⾮常简洁,并不需要很多的机器学习/深度学习知识,这也让更多 .NET 开发者能更快使⽤ ML.NET 到项⽬中来。

小结

.NET 7 在 .NET 6 基础上做了加⼀的操作,让 .NET 朝着更好的⾃⼰⼜迈进了⼀步。对于众多 .NET 开发者⽽⾔,我们会继续拥抱 .NET,当然也希望有更多的⼈加⼊到 .NET 的开发⼤家庭中来。.NET 7 并不是终点,每次版本的发布都是⼀个重新的起点。希望 .NET 越来越好。

ps :这次 .NET Conf 2022 不仅有 .NET 7, 官⽹也更新了,更加直观好⽤,⼤家快快上去看看!

相关文档

前往官方博客,查看.NET 7发布详情~