Mark!20 个 .NET 6 新增的 API
.NET 6 引入了两种期待已久的类型 - DateOnly 和 TimeOnly, 它们分别代表 DateTime 的日期和时间部分。
DateOnly dateOnly = new ( 2021 , 9 , 25 );
Console . WriteLine ( dateOnly );
TimeOnly timeOnly = new ( 19 , 0 , 0 );
Console . WriteLine ( timeOnly );
DateOnly dateOnlyFromDate = DateOnly . FromDateTime ( DateTime . Now );
Console . WriteLine ( dateOnlyFromDate );
TimeOnly timeOnlyFromDate = TimeOnly . FromDateTime ( DateTime . Now );
Console . WriteLine ( timeOnlyFromDate );
它可以控制多个异步任务的并行度。
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} Bio: {user.Bio} " );
});
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 的小改进, 在抛出异常之前不需要在每个方法中检查 null, 现在只需要写一行, 和 response.EnsureSuccessStatusCode(); 类似。
ExampleMethod ( null );
void ExampleMethod ( object param )
{
ArgumentNullException . ThrowIfNull ( param );
// Do something
}
.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
提供基于偏移量的 API,用于以线程安全的方式读取和写入文件。
using SafeFileHandle handle = File . OpenHandle ( "file.txt" , access : FileAccess . ReadWrite );
// Write to file
byte [] strBytes = Encoding . UTF8 . GetBytes ( "Hello world" );
ReadOnlyMemory buffer1 = new ( strBytes );
await RandomAccess . WriteAsync ( handle , buffer1 , 0 );
// Get file length
long length = RandomAccess . GetLength ( handle );
// Read from file
Memory buffer2 = new ( new byte [ length ]);
await RandomAccess . ReadAsync ( handle , buffer2 , 0 );
string content = Encoding . UTF8 . GetString ( buffer2 . ToArray ());
Console . WriteLine ( content ); // Hello world
认识一个完全异步的“PeriodicTimer”, 更适合在异步场景中使用, 它有一个方法 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 规范, 内置了指标API, 通过 Meter 类创建下面的指标
•Counter
•Histogram
•ObservableCounter
•ObservableGauge
使用的方法如下:
var builder = WebApplication . CreateBuilder ( args );
var app = builder . Build ();
// Create Meter
var meter = new Meter ( "MetricsApp" , "v1.0" );
// Create counter
Counter counter = meter . CreateCounter ( "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 (( instrument , measurement , tags , state ) =>
{
Console . WriteLine ( $ "Instrument {instrument.Name} has recorded the measurement: {measurement}" );
});
listener . Start ();
}
它提供来自反射成员的可空性信息和上下文:
•ParameterInfo 参数
•FieldInfo 字段
•PropertyInfo 属性
•EventInfo 事件
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 ; }
}
它允许您获取嵌套元素的可为空的信息, 您可以指定数组属性必须为非空,但元素可以为空,反之亦然。
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 ; }
}
直接通过 Environment 获取进程ID和路径。
int processId = Environment . ProcessId
string path = Environment . ProcessPath ;
Console . WriteLine ( processId );
Console . WriteLine ( path );
和 DI 的 GetRequiredService() 是一样的, 如果缺失, 则会抛出异常。
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 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 );
}*/
}
.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
您可以更轻松地等待异步任务执行, 如果超时会抛出 “TimeoutException”
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.
新方法:
•SinCos
•ReciprocalEstimate
•ReciprocalSqrtEstimate
新的重载:
•Min, Max, Abs, Sign, Clamp 支持 nint 和 nuint
•DivRem 返回一个元组, 包括商和余数。
// New methods SinCos, ReciprocalEstimate and ReciprocalSqrtEstimate
// Simultaneously computes Sin and Cos
( double sin , double cos ) = Math . SinCos ( 1.57 );
Console . WriteLine ( $ "Sin = {sin} Cos = {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} Max = {max} Abs = {abs}" );
Console . WriteLine ( $ "Clamp = {clamp} Sign = {sign}" );
// DivRem variants return a tuple
( int quotient , int remainder ) = Math . DivRem ( 2 , 7 );
Console . WriteLine ( $ "Quotient = {quotient} Remainder = {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
这个是在字典中循环或者修改结可变结构体时用, 可以减少结构的副本复制, 也可以避免字典重复进行哈希计算,这个有点晦涩难懂,有兴趣的可以看看这个
https://github.com/dotnet/runtime/issues/27062
Dictionary < int , MyStruct > dictionary = new ()
{
{ 1 , new MyStruct { Count = 100 } }
};
int key = 1 ;
ref MyStruct value = ref CollectionsMarshal . GetValueRefOrNullRef ( dictionary , key );
// Returns Unsafe.NullRef () 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 上的新 ConfigureHostOptions 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 方法, 当您处理 IAsyncDisposable 的服务时现有的 CreateScope 方法会引发异常, 使用 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 ;
}
•DecryptCbc
•DecryptCfb
•DecryptEcb
•EncryptCbc
•EncryptCfb
•EncryptEcb
static byte [] Decrypt ( byte [] key , byte [] iv , byte [] ciphertext )
{
using ( Aes aes = Aes . Create ())
{
aes . Key = key ;
return aes . DecryptCbc ( ciphertext , iv , PaddingMode . PKCS7 );
}
}
天炎康赛: //////////////////最简单的了////////////////////////////////// The Minarr is arr[6]=2 Press any key to continue#include #include #include main() { int i,Minarr,Mark,arr[20]; srand((unsigned)time(NULL)); for (i=0;i { arr[i]= rand()%100; if (i==0) Minarr = arr[i]; else if (arr[i] { ...
华县17186522202: 在ROS中设置电信网通双ADSL - ?
天炎康赛: 1、先添加双线IP地址,我这里分别是:第一条 192.168.10.2/24 网关192.168.10.1 [公网] 第二条 192.168.20.2/24 网关 192.168.20.1 [公网] 内网 ROS IP地址为192.168.30.1 [内网]2、添加两个外网的网关并且做好标记 命令如下:[admin@lan] > ...
华县17186522202: ⑴ 随机产生20个学生的VB程序设计课程的成绩,存入一维数组中,并显示结果; - ?
天炎康赛: Randomize Dim a(20) Dim s1, s2, s3, s4, s5, s6 s1 = 0: s2 = 0: s3 = 0: s4 = 0: s5 = 0: s6 = 0 For i = 0 To 19 a(i) = Round(100 * Rnd(1)) Print a(i); Next Print For i = 0 To 19 If a(i) >= 50 And a(i) <= 59 Then s1 = s1 + 1 If a(i) >= 60 And a(i) <= 69 Then ...
华县17186522202: .net 怎么按每20个字符分割一次 - ?
天炎康赛: net(C#)中用split分割字符串的用法与ASP中基本相同,只是写法略有区别: string a="1-2-3-4-5-6-7-8-9"; string[] b = a.Split(new Char[] { '-' }); for (int i = 0; i
华县17186522202: C程序设计题 一维数组 - ?
天炎康赛: #include "stdio.h" #include "math.h" int main() { int i,d[20],t[20],j,k,n,mark,temp; printf("输入20个整数:"); n=0;k=0; for(i=0;i<20;i++) { scanf("%d",&d[i]);//输入整数(20个) //判断d[i]是否是素数 mark=0; for(j=2;j<sqrt(d[i]);j++) { if(d[i]...
华县17186522202: 一、选择题(每题2分,共30分) 1.将C++源程序进行 可得到目标文件( ) A.编辑 B.编译 C.连接 D.拼 - ?
天炎康赛: C语言编译的整个过程是非常复杂的,一般情况下,我们只需要知道分成编译和连接两个阶段,编译阶段将源程序(*.c)转换成为目标代码(,一般是obj文件,至于具体过程就是上面说的那些阶段),连接阶段是把源程序转换成的目标代码(...