.NET 每周分享第 35 期
卷首语

从诞生的第一天起, C# 就被认为是 Java 的模仿者。从历史来看,我们不能否认这一个观点。现在,每个编程语言都借鉴了其他的编程语言,那么从 .NET Core 之后,C# 又从 Java 中借鉴了什么呢?主要包含三个
- Record 类型
Record 类型是用来表示纯数据的结构,C# 编译器能够将它转换成一个 class 类型,并且重写了 Equals 方法。
- 字面字符串
在 C# 中,我们使用双引号 " 来表示一个字符串,但是对于一些复杂的字符串,比如换行,特殊字符,我们需要通过转义的方式来表示。这样带来了很多使用的不便。C# 引入的字面字符串的方式
var text = """
{
"name": "fung kao"
}
""";
- 枚举类型的箭头表达
对于枚举类型,我们一般采用 swtich 的方式,比如
enum Role
{
User,
Admin
}
var role = Role.User;
switch(role)
{
case Role.User:
Console.WriteLine("User");
break;
case Role.Admin:
Console.WriteLine("Admin");
break;
default:
Console.WriteLine("Unknown");
break;
}
这是这个常见的用法,C# 引入了模式匹配的方式,我们可以这样使用
var text = role swtich
{
Role.User => "User",
Role.Admin => "Admin"
_ => "unknown"
}
行业资讯

通常而言,英语是 .NET 社区常用的沟通语言。但是最近 .NET 社区举办了全球的虚拟大会,而且在不同的时区和不同语言,值得大家参加。
文章推荐

C# 中包含了很多 Timer 类,一般都用来进行一些定时的操作。主要分为两大类:
- UI 定时类
System.Windows.Forms.TimerSystem.Windows.Threading.DispatcherTimer它们都是 UI 线程执行回调,所以它们能够更新 UI 上的元素,而且每次只执行一次,因此不用担心线程安全的问题
- 通用定时器
System.Threading.TimerSystem.Threading.PeriodicTimerSystem.Timers.Timer
其中 System.Threading.Timer 是最基础的定时器,它将回调委托给线程池执行。但是如果回调执行的时间超过定时器的间隔,那么会发生同时执行多次的情况。
var timer = new System.Threading.Timer(
callback: state => Console.WriteLine("tick"), // callback can be executed in parallel
// if the previous one is not completed
// before the next tick
state: null, // Can be used to pass data to the callback (to avoid using a closure)
dueTime: TimeSpan.Zero, // Start the timer immediately
period: TimeSpan.FromSeconds(1)); // Tick every second
// Pause the timer
timer.Change(dueTime: Timeout.Infinite, period: Timeout.Infinite);
System.Timer.Timer 是对 System.Threading.Timer 的封装,而且暴露了其他几个方法,比如 AutoReset, Enabled,SynchronizingObject 等等,而且它还支持多个回调的调用。
var timer = new System.Timers.Timer(TimeSpan.FromSeconds(1));
// Support multiple handlers
timer.Elapsed += (sender, e) => Console.WriteLine("Handler 1");
timer.Elapsed += (sender, e) => Console.WriteLine("Handler 2");
// Support customizing the way the callback is executed (on the ThreadPool if not set)
timerComponent.SynchronizingObject = ...;
// Stop the timer after the first tick
timerComponent.AutoReset = false;
// Start the timer
timer.Start();
System.Threading.PeriodicTimer 是最近加入的类型,它的主要功能是允许定时器在循环中使用,而且执行异步。
using var cts = new CancellationTokenSource();
using var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(1));
// Simple usage, no concurrent callbacks, supports async _handlers_
while (await periodicTimer.WaitForNextTickAsync(cts.Token))
{
Console.WriteLine("Tick");
await AsyncOperation();
}
通过 while 循环判断,避免了回调的并行执行。

.NET Standard 作为一个短暂的技术名词,在 .NET 历史中存在过一段时间。主要目的是解决 .NET 各个平台的之间代码的复用性,比如 .NET Framework, Mono 或者 .NET Core。它是一组 API 定义的集合,而各个平台包含这些 API 的实现。

将一个对象实例和字符串之间相互转换是很常见的要求,在 C# 中定义了接口来进行这些转换。
- 对象实例转换字符串
- IFormattable
- ISpanFormattable
只要对象实现了其中的接口,那么可以将对象实例按照要求转换成字符串类型
- 字符串转换成对象
- IParsable
- ISpanParsable
.NET 7 为接口类型提供了静态方法,所以在 .NET 7 之前,将一个字符串转换成对象的话,通常是这么处理的
class Person {
public string FirstName { get; }
public string FullName { get; }
public string Country { get; }
public Person(string firstName, string fullName, string country) {
FirstName = firstName;
FullName = fullName;
Country = country;
}
}
static class ExtensionMethods {
internal static Person Parse(this string s) {
string[] strings = s.Split(new[] { ',', ';' });
if(strings.Length != 3) { throw new OverflowException("Expect: FirstName,LastName,Country"); }
return new Person(strings[0], strings[1], strings[2]);
}
}
通常我们需要编写 string 类型的扩展方法,那么在 .NET 7 中,我们可以通过集成 IParsable 接口完成更优雅的实现方式。
sealed class Person : IParsable<Person> {
public string FirstName { get; }
public string FullName { get; }
public string Country { get; }
// Private constructor used from the Parse() method below
private Person(string firstName, string fullName, string country) {
FirstName = firstName;
FullName = fullName;
Country = country;
}
// IParsable<Person> implementation
public static Person Parse(string s, IFormatProvider? provider) {
string[] strings = s.Split(new[] { ',', ';' });
if(strings.Length != 3) { throw new OverflowException("Expect: FirstName,LastName,Country"); }
return new Person(strings[0], strings[1], strings[2]);
}
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Person result) {
result = null;
if (s == null) { return false; }
try {
result = Parse(s, provider);
return true;
} catch { return false; }
}
}
Person person = "Bill,Gates,US".Parse<Person>();

作为一名 .NET 开发者,该如何上手 Azure OpenAI 呢?这篇官方博客给出了建议。
5、ASP.NET Core 中间件处理流程

6、WASM 介绍

WASM 是新的技术,.NET 也不能落后,这个幻灯片介绍了 WASM 和 C# 入门知识。
Mutation Test 是用来检测单元测试的质量,这个视频详细介绍这个概念。
开源项目

ChatGPT 火了,各种针对 OpenAI 的 API 开发的 AI 应用程序也数不胜数。 PowerShellAI 是一个开源的 PowerShell 库,使用它我们可以在 Powershell 中使用我们的人工智能助手。
2、.NET 知名开源库
