.NET 6 中的 20 个新 API

DateOnlyTimeOnly

.NET 6 引入了两种期待已久的类型 - DateOnlyTimeOnly。它们表示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);
    }
}

 

posted @ 2021-12-31 14:36  Tammytan  阅读(459)  评论(2编辑  收藏  举报