Liam W
封面

由社区推动的 .NET 6 新 API

作者
王亮·发表于 2 年前

原文:https://bit.ly/3ykXfgJ
作者:David Fowler
翻译:精致码农-王亮

.NET 6 即将到来,我想分享一些我最喜欢的 .NET 和 ASP.NET Core 中的新 API,你一定会喜欢,因为它们是由我们优秀的 .NET 开发者社区推动的。让我们开始吧!

读写文件

在 .NET 6 中,有一个新的底层 API,可以在不使用 FileStream 的情况下实现文件的读/写。它还支持分散/聚集 IO(多个缓冲区)和在给定文件偏移处的重叠读写:

using Microsoft.Win32.SafeHandles;
using SafeFileHandle handle = File.OpenHandle("ConsoleApp128.exe");
long length = RandomAccess.GetLength(handle);

Console.WriteLine(length);

进程路径和 ID

有几种新的方法可以在不分配新进程对象的情况下访问进程路径和进程 ID:

int pid = Environment.ProcessId;
string path = Environment.ProcessPath;

Console.WriteLine(pid);
Console.WriteLine(path);

CSPNG

CSPNG(Cryptographically Secure Pseudorandom Number Generator) 生成随机数比以往更容易:

// Give me 200 random bytes
byte[] bytes = RandomNumberGenerator.GetBytes(200);

Parallel.ForEachAsync

我们最终添加了 Parallel.ForEachAsync,这是一种允许你控制并行异步工作的方法:

var urlsToDownload = new []
{
    "https://dotnet.microsoft.com",
    "https://www.microsoft.com",
    "https://twitter.com/davidfowl"
};

var client = new HttpClient();

await Parallel.ForEachAsync(urlsToDownload, async (url, token) =>
{
    var targetPath = Path.Combine(Path.GetTempPath(), "http_cache", url);

    HttpResponseMessage response = await client.GetAsync(url);

    if (response.IsSuccessStatusCode)
    {
        using FileStream target = File.OpenWrite(targetPath);

        await response.Content.CopyToAsync(target);
    }
});

配置辅助

我们添加了一个辅助功能,使其更容易在配置中缺失必要部分时抛出异常:

var configuration = new ConfigurationManager();
var options = new MyOptions();

// This will throw if the section isn't configured
configuration.GetRequiredSection("MyOptions").Bind(options);

class MyOptions
{
    public string? SettingValue { get; set;}
}

LINQ

还有大量的新的 LINQ 方法。在这个版本中,它广受开发者喜爱。这里有一个新的辅助方法,可以将任何 IEnumerable 集合分块成批:

int chunkNumber = 1;
foreach (int[] chunk in Enumerable.Range(0, 9).Chunk(3))
{
    Console.WriteLine(
quot;Chunk
{chunkNumber++}"
); foreach (var item in chunk) { Console.WriteLine(item); } }

更多的 LINQ

更多的 LINQ!现在有了 MaxByMinBy 方法:

var people = GetPeople();

var oldest = people.MaxBy(p => p.Age);
var youngest = people.MinBy(p => p.Age);

Console.WriteLine(
quot;The oldest person is
{oldest.Age}"
); Console.WriteLine(
quot;The youngest person is
{youngest.Age}"
); public record Person(string Name, int Age);

2 的幂

不想在脑子里做位运算?我也不想。这里有一些用于处理 2 的幂的新辅助方法:

using System.Numerics;

uint bufferSize = 235;
if (!BitOperations.IsPow2(bufferSize))
{
    bufferSize = BitOperations.RoundUpToPowerOf2(bufferSize);
}

Console.WriteLine(bufferSize);

WaitAsync 改进

现在有一种更简单(并且正确实现)的方法来异步等待任务的完成。该操作可能仍在运行 这是为不可取消的操作准备的!

Task operationTask = SomeLongRunningOperationAsync();

await operationTask.WaitAsync(TimeSpan.FromSeconds(10));

ThrowIfNull

不再需要在抛出异常之前在每个方法中检查 null。现在只需要一行代码了:

void DoSomethingUseful(object obj)
{
    ArgumentNullException.ThrowIfNull(obj);
}

使用 NativeMemory

如果你想使用 C 语言的 API 来分配内存,因为你是一个 l33t 黑客,或者需要分配本地内存,那么现在有了。不要忘记释放!

using System.Runtime.InteropServices;

unsafe
{
    byte* buffer = (byte*)NativeMemory.Alloc(100);

    NativeMemory.Free(buffer);
}

Posix 信号处理

现在有了对 Posix 信号处理的本地支持,我们也在 Windows 上模拟了几个信号:

using System.Runtime.InteropServices;

var tcs = new TaskCompletionSource();

PosixSignalRegistration.Create(PosixSignal.SIGTERM, context =>
{
    Console.WriteLine(
quot;
{context.Signal} fired"
); tcs.TrySetResult(); }); await tcs.Task;

新的 Metric API

我们在 .NET 6 中基于 @opentelemetry 添加了一个全新的 Metric API。它支持维度,高效,并将为流行的 Metric 槽提供导出:

using System.Diagnostics.Metrics;

// This is how you produce metrics

var meter = new Meter("Microsoft.AspNetCore", "v1.0");
Counter<int> counter = meter.CreateCounter<int>("Requests");

var app = WebApplication.Create(args);

app.Use((context, next) =>
{
    counter.Add(1, KeyValuePair.Create<string, object?>("path", context.Request.Path.ToString()));
    return next(context);
});

app.MapGet("/", () => "Hello World");

你甚至可以监听并测算:

var listener = new MeterListener();
listener.InstrumentPublished = (instrument, meterListener) =>
{
    if(instrument.Name == "Requests" && instrument.Meter.Name == "Microsoft.AspNetCore")
    {
        meterListener.EnableMeasurementEvents(instrument, null);
    }
};

listener.SetMeasurementEventCallback<int>((instrument, measurement, tags, state) =>
{
    Console.WriteLine(
quot;Instrument:
{instrument.Name} has recorded the measurement: {measurement}"
); }); listener.Start();

定时器 API

最后但并非最不重要的是,一个现代的定时器 API(我想这是.NET 中的第五个定时器 API 了)。它是完全异步的,并且不受其他定时器的问题困扰,比如对象生命周期问题,没有异步回调等等。

var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));

while (await timer.WaitForNextTickAsync())
{
    Console.WriteLine(DateTime.UtcNow);
}

总结

这只是 .NET 6 中新 API 的一分部。想要了解更多信息,请看 .NET 6 发布说明中的 API 差异。另外,Stephen 刚刚写了一篇关于.NET 6 的性能改进的精彩博文,请务必阅读。最后,别忘了下载 .NET 6 预览版,今天就来试试新的 API。

.NET 6 release notes API diffs
https://github.com/dotnet/core/tree/main/release-notes/6.0/preview/api-diff

Performance Improvements in .NET 6
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6