Skip to content

Latest commit

 

History

History
211 lines (141 loc) · 7.33 KB

episode-049.md

File metadata and controls

211 lines (141 loc) · 7.33 KB

.NET 每周分享第 49 期

卷首语

C# 成为年度语言? 这里有一个有趣的不同的观点。

在过去的一段时间,.NET 社区最大的新闻是 C# 被 Tiobe 评选为 2023 年度编程语言。几乎所有的媒体都在欢呼雀跃,那么事实真的如此吗?

  1. Tiobe 评选的标准是增加量
  2. 结果并不会改变立刻任何事情
  3. Tiobe 的选择的可靠性不高

文章推荐

1、StringValue 探秘

在 Microsoft.Extensions.Primitives 包中有一个类型是 StringValues, 它可以用在表示 HTTP Header 中,可以表达三种情况,

  1. 没有 Header
  2. 单个 Header
  3. 多个 Header

那么在 ASP.NET Core 中,该如何表示这个对象呢?

  • 朴素表达方式

使用 Dictionary<string, string[]> 类型表达,因为上述三种情况都可以表示,但是这个存在两个问题:

  1. 大部分情况下,只有一个值,但是还是需要多个情况
  2. 将单个值存储为一个数组,增加内存分配
  • NameValueCollection

在 ASP.NET 中使用 NameValueCollection 类型,但是它本质还是使用 ArrayList 存储内容, 所以还是不够优雅。

在 StringValues 使用一个 object 表示上述的三种情况,也是一个 readonly struct 类型。

2、.NET 8 中 Random

image

.NET 8 在 Random 类中提供了一些新的方法,比如

  1. GetItems

当我们在一个集合中随机选择一定数量时候,可以使用 GetItems, 比如 Random.Shard.GetItems。

  1. Shuffle

如果对一个集合进行混洗,可以使用 Shuffle, 比如 Random.Shard.Shuffle。

3、.NET 8 中并行启动 IHostedService

image

在 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);
    }
}

4、查看 JIT 代码的三种方法

C# 支持查看 JIT 生成的机器代码,那么该如何查看它们呢?有三种方法

  1. DOTNET_JitDisasm="Method"
Foo.Bar(); 
class Foo
{
    public static void Bar()
    {
        Console.WriteLine("Hello World!");
    }
}

如果设置 DOTNET_JitDisasm="BAR" ,那么在执行这个方法的时候,就能看到生成 JIT 代码

  1. Disasmo

Disasmo 是 Visual Studio 的插件,用来查看生成的 JIT 代码。

  1. Sharplab

Sharplab 是一个非常有用的 Web 站点,它可以对相关的代码生成相应的 JIT 代码方便查看。

5、DTO 和 POCO 的区别

image

DTO 和 POCO 是在开发工程中经常遇到的概念,那么它们区别是怎样的呢?

  • DTO

DTO 是 Data Transfer Object 的简写,它表明只是传递数据,而不包含逻辑和行为。在 C# 中就是只有只有属性,而不是有方法或者属性的注解。

  • POCO

POCO 是 Plain Old CLR Object 的简称,它表明这个类不依赖任何第三方的库或者框架。

6、.NET 最快的 1BRC

在今年开始的时候,GitHub 爆火了 ”十亿行挑战" 活动。从原先的 Java 语言到所有开发语言。在 .NET 范围内,目前最快记录是 1.297 秒,作者介绍了自己的优化之路。

开源项目

1、NuGet Resolver

image

在一些大型 .NET 项目中,常常会遇到依赖冲突的问题,比如

  • 无法解析依赖的一致性问题
  • 依赖包不包含适合项目的资源包
  • 依赖的包版本大于最终解析版本

等等问题,Nuget 团队和 MSR 团队合作,推出了 NuGetSolver 中 Visual Studio 插件,它可以解决上述的问题。但是目前有一些限制

  1. 只支持 nuget.org 源
  2. 不支持多个源
  3. 不支持自动更新版本
  4. 不支持 preview 版本
  5. package.config 等老式版本不支持
  6. 只支持编译依赖冲突

2、Rx.NET

image

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();

3、MSTest Runner

image

微软推出了 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 就可以运行单元测试。