.NET 每周分享第 49 期
卷首语
C# 成为年度语言? 这里有一个有趣的不同的观点。
在过去的一段时间,.NET 社区最大的新闻是 C# 被 Tiobe 评选为 2023 年度编程语言。几乎所有的媒体都在欢呼雀跃,那么事实真的如此吗?
- Tiobe 评选的标准是增加量
- 结果并不会改变立刻任何事情
- Tiobe 的选择的可靠性不高
文章推荐
在 Microsoft.Extensions.Primitives 包中有一个类型是 StringValues, 它可以用在表示 HTTP Header 中,可以表达三种情况,
- 没有 Header
- 单个 Header
- 多个 Header
那么在 ASP.NET Core 中,该如何表示这个对象呢?
- 朴素表达方式
使用 Dictionary<string, string[]> 类型表达,因为上述三种情况都可以表示,但是这个存在两个问题:
- 大部分情况下,只有一个值,但是还是需要多个情况
- 将单个值存储为一个数组,增加内存分配
NameValueCollection
在 ASP.NET 中使用 NameValueCollection 类型,但是它本质还是使用 ArrayList 存储内容, 所以还是不够优雅。
在 StringValues 使用一个 object 表示上述的三种情况,也是一个 readonly struct 类型。
.NET 8 在 Random 类中提供了一些新的方法,比如
- GetItems
当我们在一个集合中随机选择一定数量时候,可以使用 GetItems, 比如 Random.Shard.GetItems。
- Shuffle
如果对一个集合进行混洗,可以使用 Shuffle, 比如 Random.Shard.Shuffle。
在 IHost 中,在执行 Run 方法的时候,会获取所有的注册的 IHostedService 取出来,然后执行 StartAsync 方法。要注意的是这个方法是顺序执行的,在 .NET 8 中,可以设置 HostOption 的 ServicesStartConcurrently 和 ServicesStopConcurrently 方法让启动或者停止并行执行。
new HostBuilder()
.ConfigureServices(service =>
{
service.Configure<HostOptions>(options =>
{
options.ServicesStartConcurrently = true;
options.ServicesStopConcurrently = true;
});
service.AddHostedService<FooService>();
service.AddHostedService<BarService>();
})
.Build()
.Run();
internal class FooService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Start Foo");
await Task.Delay(2000);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Stop Foo");
await Task.Delay(2000);
}
}
internal class BarService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Start Bar");
await Task.Delay(1000);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Stop Bar");
await Task.Delay(1000);
}
}
C# 支持查看 JIT 生成的机器代码,那么该如何查看它们呢?有三种方法
- DOTNET_JitDisasm="Method"
Foo.Bar();
class Foo
{
public static void Bar()
{
Console.WriteLine("Hello World!");
}
}
如果设置 DOTNET_JitDisasm="BAR" ,那么在执行这个方法的时候,就能看到生成 JIT 代码
- Disasmo
Disasmo 是 Visual Studio 的插件,用来查看生成的 JIT 代码。
- Sharplab
Sharplab 是一个非常有用的 Web 站点,它可以对相关的代码生成相应的 JIT 代码方便查看。
DTO 和 POCO 是在开发工程中经常遇到的概念,那么它们区别是怎样的呢?
- DTO
DTO 是 Data Transfer Object 的简写,它表明只是传递数据,而不包含逻辑和行为。在 C# 中就是只有只有属性,而不是有方法或者属性的注解。
- POCO
POCO 是 Plain Old CLR Object 的简称,它表明这个类不依赖任何第三方的库或者框架。
在今年开始的时候,GitHub 爆火了 ”十亿行挑战" 活动。从原先的 Java 语言到所有开发语言。在 .NET 范围内,目前最快记录是 1.297 秒,作者介绍了自己的优化之路。
开源项目
在一些大型 .NET 项目中,常常会遇到依赖冲突的问题,比如
- 无法解析依赖的一致性问题
- 依赖包不包含适合项目的资源包
- 依赖的包版本大于最终解析版本
等等问题,Nuget 团队和 MSR 团队合作,推出了 NuGetSolver 中 Visual Studio 插件,它可以解决上述的问题。但是目前有一些限制
- 只支持
nuget.org源 - 不支持多个源
- 不支持自动更新版本
- 不支持 preview 版本
package.config等老式版本不支持- 只支持编译依赖冲突
2、Rx.NET
Rx.NET 是一个开源的 .NET 事件库,可以帮助实现响应式编程,这样你的代码只需要响应对应的事件。
using System.Reactive.Linq;
IObservable<long> ticks = Observable.Timer(
dueTime: TimeSpan.Zero,
period: TimeSpan.FromSeconds(1));
ticks.Subscribe(tick => Console.WriteLine($"Tick {tick}"));
Console.ReadKey();
微软推出了 MSTest Runner 这个测试框架,它更加轻量级,测试更快并且提供更加便携的测试机制。主要修改两个地方
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Enable the MSTest runner, this is an opt-in feature -->
<EnableMSTestRunner>true</EnableMSTestRunner>
<!-- We need to produce an executable and not a DLL -->
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="3.2.0" />
</ItemGroup>
</Project>
这样只需要执行生成的 exe 就可以运行单元测试。