20 new API s in. NET 6

DateOnly and TimeOnly

. NET 6 introduces two long-awaited types - DateOnly and TimeOnly. They represent the date or time portion of 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

It allows you to control the parallelism of scheduled asynchronous work.

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 is a good small improvement. There is no need to check for null in each method before throwing an exception. Now it's a line.

ExampleMethod(null);

void ExampleMethod(object param)
{
    ArgumentNullException.ThrowIfNull(param);
    // Do something
}

PriorityQueue

Yes NET 6. PriorityQueue represents the lowest priority queue. Each element is queued with an associated priority that determines the de queueing order. The lowest numbered element is dequeued first.

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

Read and write files

. NET 6 introduces a new low-level API for reading and writing files without FileStream. A new type of RandomAccess provides an offset based API for reading and writing files in a thread safe manner.

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

New cycle timer

Satisfy a fully asynchronous "periodic timer". It allows asynchronous waiting for the timer to tick. It has a method, 'WaitForNextTickAsync', which waits for the next tick of the timer or the timer stops.

// 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
// ...

Index interface

. NET 6 implements the OpenTelemetry Metrics API specification. The instrument class creates an instrument object. There are instruments:

  • Counter
  • histogram
  • Observable counter
  • Observable measuring tool

You can even listen to the meter.

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

Reflection API for nullability information

It provides nullable information and context from reflection members:

  • parameter information
  • Field information
  • Attribute information
  • Event information
    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; }
    }

    Reflection API for nesting nullability information

    It allows you to get nested nullability information. You can specify that the array property must be non null, but the element can be null, and vice versa. You can get nullability information of array elements.

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

    Process path and ID

    You can access the process path and ID without assigning a new process instance.

    int processId = Environment.ProcessId
    string path = Environment.ProcessPath;
    
    Console.WriteLine(processId);
    Console.WriteLine(path);

    New configuration helper

    Yes NET 6 added a new configuration helper "GetRequiredSection". An exception is thrown if the required configuration section is missing.

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

    photoelectricity

    You can easily generate a sequence of random values from an encrypted secure pseudo-random number generator (CSPNG).

    It applies to encryption applications that:

  • Key generation
  • Nuns
  • Salt in some signature schemes
// 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);

Native memory interface

. NET 6 introduces a new API to allocate native memory. The new NativeMemory type has methods for allocating and freeing memory.

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);
    }*/
}

Power of 2

. NET 6 introduces a new helper to use the power of 2.

 

  • IsPow2 evaluates whether the specified value is a power of 2.
  • RoundUpToPowerOf2 rounds the specified value to a power of 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

Asynchronous on wait task

You can more easily wait for tasks to finish executing asynchronously. When the operation timeout expires, a timeout exception is thrown.

⚠️ This is an operation that cannot be cancelled!

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.

New math API

new method:

  • New Coase
  • Reciprocal estimation
  • ReciprocalSqrtEstimate

New overload:

  • Min, Max, ABS, symbol, clamp support, matte and asymptomatic
  • DivRem variant returns tuples
// 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

It returns a reference to a structure value that can be updated in place. It is not used for general purposes, but for high-performance solutions.

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

Configure host options

New configuration host option API on IHostBuilder. It makes application setup easier.

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

Create asynchronous scope

. NET 6 introduces a new CreateAsyncScope method for creating AsyncServiceScope. The existing CreateScope method throws an exception when releasing the IAsyncDisposable service. CreateAsyncScope provides a simple solution.

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

Simplified encryption operation call mode

New method on symmetricalalgorithm to avoid streams if the payload is already in memory:

  • decrypt
  • decrypt
  • decrypt
  • Encrypted Cbc
  • EncryptCfb
  • EncryptEcb

They provide a simple way to use the encryption 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);
    }
}

 

Keywords: net

Added by delldeveloper on Sat, 01 Jan 2022 03:57:18 +0200