DateOnly & TimeOnly
。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
);
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, 現在只需要寫一行, 和
response。EnsureSuccessStatusCode();
類似。
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
RandomAccess
提供基於偏移量的 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
認識一個完全非同步的“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
// 。。。
Metrics API
。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
();
}
檢查元素是否可為空的反射API
它提供來自反射成員的可空性資訊和上下文:
•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
;
}
}
檢查巢狀元素是否可為空的反射API
它允許您獲取巢狀元素的可為空的資訊, 您可以指定陣列屬性必須為非空,但元素可以為空,反之亦然。
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
;
}
}
ProcessId & ProcessPath
直接透過 Environment 獲取程序ID和路徑。
int
processId
=
Environment
。
ProcessId
string
path
=
Environment
。
ProcessPath
;
Console
。
WriteLine
(
processId
);
Console
。
WriteLine
(
path
);
Configuration 新增 GetRequiredSection()
和 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 密碼安全偽隨機數生成器
您可以從密碼安全偽隨機數生成器 (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
[]
bytes
=
RandomNumberGenerator
。
GetBytes
(
300
);
Native Memory API
。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
);
}*/
}
Power of 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
WaitAsync on Task
您可以更輕鬆地等待非同步任務執行, 如果超時會丟擲 “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。
新的數學API
新方法:
•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}\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
這個是在字典中迴圈或者修改結可變結構體時用, 可以減少結構的副本複製, 也可以避免字典重複進行雜湊計算,這個有點晦澀難懂,有興趣的可以看看這個
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
(!
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
;
}
}
ConfigureHostOptions
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
);
});
}
Async Scope
。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
);
}
}
[1] Oleg Kyrylchuk: https://hashnode。com/@okyrylchuk
文章來源於全球技術精選 ,作者Oleg Kyrylchuk