.NET 6 中的 20 个新 API
DateOnly和TimeOnly
.NET 6 引入了两种期待已久的类型 - DateOnly和TimeOnly。它们表示DateTime的日期或时间部分。
// public DateOnly(int year, int month, int day) // public DateOnly(int year, int month, int day, Calendar calendar) DateOnly dateOnly = new(2021, 9, 25); Console.WriteLine(dateOnly); // Output: 25-Sep-21 // public TimeOnly(int hour, int minute) // public TimeOnly(int hour, int minute, int second) // public TimeOnly(int hour, int minute, int second, int millisecond) // public TimeOnly(long ticks) TimeOnly timeOnly = new(19, 0, 0); Console.WriteLine(timeOnly); // Output: 19:00 PM DateOnly dateOnlyFromDate = DateOnly.FromDateTime(DateTime.Now); Console.WriteLine(dateOnlyFromDate); // Output: 23-Sep-21 TimeOnly timeOnlyFromDate = TimeOnly.FromDateTime(DateTime.Now); Console.WriteLine(timeOnlyFromDate); // Output: 21:03 PM
Parallel.Foreachasync
它允许您控制计划的异步工作的并行度。
var userHandlers = new[] { "users/okyrylchuk", "users/jaredpar", "users/davidfowl" }; using HttpClient client = new() { BaseAddress = new Uri("https://api.github.com"), }; client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("DotNet", "6")); ParallelOptions options = new() { MaxDegreeOfParallelism = 3 }; await Parallel.ForEachAsync(userHandlers, options, async (uri, token) => { var user = await client.GetFromJsonAsync<GitHubUser>(uri, token); Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}\n"); }); public class GitHubUser { public string Name { get; set; } public string Bio { get; set; } } // Output: // Name: David Fowler // Bio: Partner Software Architect at Microsoft on the ASP.NET team, Creator of SignalR // // Name: Oleg Kyrylchuk // Bio: Software developer | Dotnet | C# | Azure // // Name: Jared Parsons // Bio: Developer on the C# compiler
ArgumentNullException.ThrowIfNull()
ArgumentNullException的很好的小改进。在引发异常之前,无需在每个方法中检查 null。现在它是一行。
ExampleMethod(null); void ExampleMethod(object param) { ArgumentNullException.ThrowIfNull(param); // Do something }
PriorityQueue
在 .NET 6 中了解新的数据结构。PriorityQueue 表示最低优先级队列。每个元素都使用确定取消排队顺序的关联优先级进行排队。编号最低的元素首先取消排队。
PriorityQueue<string, int> priorityQueue = new(); priorityQueue.Enqueue("Second", 2); priorityQueue.Enqueue("Fourth", 4); priorityQueue.Enqueue("Third 1", 3); priorityQueue.Enqueue("Third 2", 3); priorityQueue.Enqueue("First", 1); while (priorityQueue.Count > 0) { string item = priorityQueue.Dequeue(); Console.WriteLine(item); } // Output: // First // Second // Third 2 // Third 1 // Fourth
读取和写入文件
.NET 6 引入了一个新的低级 API,用于在没有 FileStream 的情况下读取和写入文件。一种新类型 RandomAccess 提供了基于偏移量的 API,用于以线程安全的方式读取和写入文件。
using SafeFileHandle handle = File.OpenHandle("file.txt", access: FileAccess.ReadWrite); // Write to file byte[] strBytes = Encoding.UTF8.GetBytes("Hello world"); ReadOnlyMemory<byte> buffer1 = new(strBytes); await RandomAccess.WriteAsync(handle, buffer1, 0); // Get file length long length = RandomAccess.GetLength(handle); // Read from file Memory<byte> buffer2 = new(new byte[length]); await RandomAccess.ReadAsync(handle, buffer2, 0); string content = Encoding.UTF8.GetString(buffer2.ToArray()); Console.WriteLine(content); // Hello world
新的周期计时器
满足一个完全异步的"周期性计时器"。它允许异步等待计时器滴答。它有一个方法,'WaitForNextTickAsync',它等待计时器的下一个刻度或计时器停止。
// One constructor: public PeriodicTimer(TimeSpan period) using PeriodicTimer timer = new(TimeSpan.FromSeconds(1)); while (await timer.WaitForNextTickAsync()) { Console.WriteLine(DateTime.UtcNow); } // Output: // 13 - Oct - 21 19:58:05 PM // 13 - Oct - 21 19:58:06 PM // 13 - Oct - 21 19:58:07 PM // 13 - Oct - 21 19:58:08 PM // 13 - Oct - 21 19:58:09 PM // 13 - Oct - 21 19:58:10 PM // 13 - Oct - 21 19:58:11 PM // 13 - Oct - 21 19:58:12 PM // ...
指标接口
.NET 6 实现了 OpenTelemetry Metrics API 规范。"仪表"类创建仪器对象。有仪器类:
- 计数器
- 直方图
- 可观察计数器
- 可观察量具
您甚至可以收听仪表。
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); // Create Meter var meter = new Meter("MetricsApp", "v1.0"); // Create counter Counter<int> counter = meter.CreateCounter<int>("Requests"); app.Use((context, next) => { // Record the value of measurement counter.Add(1); return next(context); }); app.MapGet("/", () => "Hello World"); StartMeterListener(); app.Run(); // Create and start Meter Listener void StartMeterListener() { var listener = new MeterListener(); listener.InstrumentPublished = (instrument, meterListener) => { if (instrument.Name == "Requests" && instrument.Meter.Name == "MetricsApp") { // Start listening to a specific measurement recording meterListener.EnableMeasurementEvents(instrument, null); } }; listener.SetMeasurementEventCallback<int>((instrument, measurement, tags, state) => { Console.WriteLine($"Instrument {instrument.Name} has recorded the measurement: {measurement}"); }); listener.Start(); }
用于可空性信息的反射 API
它提供来自反射成员的可空信息和上下文:
- 参数信息
- 字段信息
- 属性信息
- 事件信息
var example = new Example(); var nullabilityInfoContext = new NullabilityInfoContext(); foreach (var propertyInfo in example.GetType().GetProperties()) { var nullabilityInfo = nullabilityInfoContext.Create(propertyInfo); Console.WriteLine($"{propertyInfo.Name} property is {nullabilityInfo.WriteState}"); } // Output: // Name property is Nullable // Value property is NotNull class Example { public string? Name { get; set; } public string Value { get; set; } }
用于嵌套可空性信息的反射 API
它允许您获取嵌套的可空性信息。可以指定数组属性必须为非 null,但元素可以为 null,反之亦然。您可以获取数组元素的可空性信息。
Type exampleType = typeof(Example); PropertyInfo notNullableArrayPI = exampleType.GetProperty(nameof(Example.NotNullableArray)); PropertyInfo nullableArrayPI = exampleType.GetProperty(nameof(Example.NullableArray)); NullabilityInfoContext nullabilityInfoContext = new(); NullabilityInfo notNullableArrayNI = nullabilityInfoContext.Create(notNullableArrayPI); Console.WriteLine(notNullableArrayNI.ReadState); // NotNull Console.WriteLine(notNullableArrayNI.ElementType.ReadState); // Nullable NullabilityInfo nullableArrayNI = nullabilityInfoContext.Create(nullableArrayPI); Console.WriteLine(nullableArrayNI.ReadState); // Nullable Console.WriteLine(nullableArrayNI.ElementType.ReadState); // Nullable class Example { public string?[] NotNullableArray { get; set; } public string?[]? NullableArray { get; set; } }
进程路径和 ID
您可以访问流程路径和 ID,而无需分配新的流程实例。
int processId = Environment.ProcessId string path = Environment.ProcessPath; Console.WriteLine(processId); Console.WriteLine(path);
新的配置帮助程序
在 .NET 6 中添加了新的配置帮助程序"GetRequiredSection"。如果缺少所需的配置节,则会引发异常。
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); WebApplication app = builder.Build(); MySettings mySettings = new(); // Throws InvalidOperationException if a required section of configuration is missing app.Configuration.GetRequiredSection("MySettings").Bind(mySettings); app.Run(); class MySettings { public string? SettingValue { get; set; } }
光电
您可以轻松地从加密安全的伪随机数生成器 (CSPNG) 生成随机值序列。
它适用于以下各项的加密应用程序:
- 密钥生成
- 侬斯
- 某些签名方案中的盐
// Fills an array of 300 bytes with a cryptographically strong random sequence of values. // GetBytes(byte[] data); // GetBytes(byte[] data, int offset, int count) // GetBytes(int count) // GetBytes(Span<byte> data) byte[] bytes = RandomNumberGenerator.GetBytes(300);
本机内存接口
.NET 6 引入了一个新的 API 来分配本机内存。新的 NativeMemory 类型具有用于分配和释放内存的方法。
unsafe { byte* buffer = (byte*)NativeMemory.Alloc(100); NativeMemory.Free(buffer); /* This class contains methods that are mainly used to manage native memory. public static class NativeMemory { public unsafe static void* AlignedAlloc(nuint byteCount, nuint alignment); public unsafe static void AlignedFree(void* ptr); public unsafe static void* AlignedRealloc(void* ptr, nuint byteCount, nuint alignment); public unsafe static void* Alloc(nuint byteCount); public unsafe static void* Alloc(nuint elementCount, nuint elementSize); public unsafe static void* AllocZeroed(nuint byteCount); public unsafe static void* AllocZeroed(nuint elementCount, nuint elementSize); public unsafe static void Free(void* ptr); public unsafe static void* Realloc(void* ptr, nuint byteCount); }*/ }
2 的幂
.NET 6 引入了新的帮助程序,用于使用 2 的幂。
- "IsPow2"评估指定的值是否为 2 的幂。
- "RoundUpToPowerOf2"将指定值舍入为 2 的幂。
// IsPow2 evaluates whether the specified Int32 value is a power of two. Console.WriteLine(BitOperations.IsPow2(128)); // True // RoundUpToPowerOf2 rounds the specified T:System.UInt32 value up to a power of two. Console.WriteLine(BitOperations.RoundUpToPowerOf2(200)); // 256
等待任务上的异步
您可以更轻松地等待任务异步完成执行。当操作超时过期时,将引发"超时异常"。
⚠️ 这是不可取消的操作!
Task operationTask = DoSomethingLongAsync(); await operationTask.WaitAsync(TimeSpan.FromSeconds(5)); async Task DoSomethingLongAsync() { Console.WriteLine("DoSomethingLongAsync started."); await Task.Delay(TimeSpan.FromSeconds(10)); Console.WriteLine("DoSomethingLongAsync ended."); } // Output: // DoSomethingLongAsync started. // Unhandled exception.System.TimeoutException: The operation has timed out.
新的数学 API
新方法:
- 新科斯
- 互惠估计
- ReciprocalSqrtEstimate
新的重载:
- 最小值、最大值、腹肌、符号、夹具支持无光和无症状
- DivRem 变体返回元组
// New methods SinCos, ReciprocalEstimate and ReciprocalSqrtEstimate // Simultaneously computes Sin and Cos (double sin, double cos) = Math.SinCos(1.57); Console.WriteLine($"Sin = {sin}\nCos = {cos}"); // Computes an approximate of 1 / x double recEst = Math.ReciprocalEstimate(5); Console.WriteLine($"Reciprocal estimate = {recEst}"); // Computes an approximate of 1 / Sqrt(x) double recSqrtEst = Math.ReciprocalSqrtEstimate(5); Console.WriteLine($"Reciprocal sqrt estimate = {recSqrtEst}"); // New overloads // Min, Max, Abs, Clamp and Sign supports nint and nuint (nint a, nint b) = (5, 10); nint min = Math.Min(a, b); nint max = Math.Max(a, b); nint abs = Math.Abs(a); nint clamp = Math.Clamp(abs, min, max); nint sign = Math.Sign(a); Console.WriteLine($"Min = {min}\nMax = {max}\nAbs = {abs}"); Console.WriteLine($"Clamp = {clamp}\nSign = {sign}"); // DivRem variants return a tuple (int quotient, int remainder) = Math.DivRem(2, 7); Console.WriteLine($"Quotient = {quotient}\nRemainder = {remainder}"); // Output: // Sin = 0.9999996829318346 // Cos = 0.0007963267107331026 // Reciprocal estimate = 0.2 // Reciprocal sqrt estimate = 0.4472135954999579 // Min = 5 // Max = 10 // Abs = 5 // Clamp = 5 // Sign = 1 // Quotient = 0 // Remainder = 2
CollectionsMarshal.GetValueRefOrNullRef
它返回对结构值的引用,该结构值可以就地更新。它不是用于常规用途,而是用于高性能方案。
Dictionary<int, MyStruct> dictionary = new() { { 1, new MyStruct { Count = 100 } } }; int key = 1; ref MyStruct value = ref CollectionsMarshal.GetValueRefOrNullRef(dictionary, key); // Returns Unsafe.NullRef<TValue>() if it doesn't exist; check using Unsafe.IsNullRef(ref value) if (!Unsafe.IsNullRef(ref value)) { Console.WriteLine(value.Count); // Output: 100 // Mutate in-place value.Count++; Console.WriteLine(value.Count); // Output: 101 } struct MyStruct { public int Count { get; set; } }
配置主机选项
IHostBuilder上的新配置主机选项API。它使应用程序设置更简单。
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureHostOptions(o => { o.ShutdownTimeout = TimeSpan.FromMinutes(10); }); }
创建异步作用域
.NET 6 引入了一种新的CreateAsyncScope方法,用于创建AsyncServiceScope。现有的CreateScope方法会在释放IAsyncDisposable服务时引发异常。CreateAsyncScope提供了一个简单的解决方案。
await using var provider = new ServiceCollection() .AddScoped<Example>() .BuildServiceProvider(); await using (var scope = provider.CreateAsyncScope()) { var example = scope.ServiceProvider.GetRequiredService<Example>(); } class Example : IAsyncDisposable { public ValueTask DisposeAsync() => default; }
简化的加密操作调用模式
SymmetricAlgorithm上的新方法,如果有效负载已在内存中,则避免流:
- 解密
- 解密
- 解密
- 加密Cbc
- EncryptCfb
- EncryptEcb
它们提供了一种使用加密 API 的简单方法。
static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext) { using (Aes aes = Aes.Create()) { aes.Key = key; return aes.DecryptCbc(ciphertext, iv, PaddingMode.PKCS7); } }