.NET 8.0 中有哪些新的變化?

.NET 8.0 中有哪些新的變化?

.NET 8在整個堆疊中帶來了數千項效能改進

最後更新 2023/11/17 下午4:03
葡萄城技术团队
預計閱讀 20 分鐘
分類
.NET
標籤
.NET C# 技術更新

1. 效能提升

.NET 8 在整個堆疊帶來了數千項效能改進。預設情況下會啟用一種名為動態設定檔引導最佳化 (PGO) 的新程式碼產生器,它可以根據實際使用情況最佳化程式碼,並且可以將應用程式的效能提高高達 20%。現在支援的 AVX-512 指令集能夠對 512 位元資料向量執行平行操作,這意味著可以在更短的時間內處理更多的資料。原始類型(數字及其他類型)現在實作了新的可格式化和可解析介面,這使它們能夠直接格式化和解析為 UTF-8,而無需任何轉碼開銷。 img

2. NET Aspire

.NET Aspire 是一個用於使用 .NET 構建彈性、可觀察和可設定的雲原生應用程式的堆疊。它包括一組針對雲原生增強的精選元件,預設情況下包括遙測、彈性、設定和健康檢查。結合複雜而簡單的本地開發人員體驗,.NET Aspire 可以在第 1 天和第 100 天輕鬆發現、獲取和設定雲原生應用程式的基本相依項。

點選這裡檢視.NET Aspire 的預覽版本。(站長注:這是沒有連結,後面看怎麼查詢補充) img

3. NET 8 容器增強功能 – 更安全、更緊湊、更高效

使用 .NET 比以往更輕鬆、更安全地使用容器打包應用程式。每個 .NET 映像都包含一個非 root 使用者,從而透過單行設定啟用更安全的容器。.NET SDK 工具無需 Dockerfile 即可發佈容器映像,並且預設情況下是非 root 的。由於 .NET 基礎映像更小,因此可以更快地部署容器化應用程式 - 包括我們映像的新實驗變體,這些變體可為本機 AOT 提供真正最小的應用程式大小。選擇使用新的 Chiseled Ubuntu 映像變體進行更多安全強化,以進一步減少攻擊面。使用 Dockerfile 或 SDK 工具,為任何架構構建應用程式和容器映像。

img

4. 原生 AoT – 邁向更高密度永續計算的旅程

無需等待 JIT(即時)編譯器在執行階段編譯程式碼。無需部署 JIT 編譯器和 IL 程式碼。AOT 應用程式僅部署應用程式所需的程式碼。應用程式現在可以在不允許使用 JIT 編譯器的受限環境中執行。

img

5. 人工智慧 – 將 AI 融入您的 .NET 應用程式

生成式人工智慧和大型語言模型正在改變人工智慧領域,使開發人員能夠在其應用程式中建立獨特的人工智慧體驗。.NET 8 可以透過 .NET SDK 中一流的開箱即用 AI 功能以及與多種工具的無縫整合來輕鬆利用 AI。

.NET 8 為該程式庫帶來了多項增強功能,以提高其與生成式 AI 工作負載的相容性,例如整合 Tensor Primitives。隨著人工智慧應用程式的興起,新的工具和 SDK 出現了。我們與眾多內部和外部合作夥伴合作,例如 Azure OpenAI、Azure Cognitive Search、Milvus、Qdrant 和 Microsoft Teams,以確保 .NET 開發人員可以透過各自的 SDK 輕鬆存取各種 AI 模型、服務和平台。此外,開源語意核心 System.Numerics SDK 簡化了這些 AI 元件與新的和現有應用程式的整合,以幫助您提供創新的使用者體驗。

現在提供各種範例和參考範本,展示模式和實踐,以便開發人員輕鬆入門:

img

6. Blazor – 使用 .NET 構建全棧 Web 應用程式

.NET 8 中的 Blazor 可以同時使用伺服器和用戶端來處理您的所有 Web UI 需求。這是全棧 Web UI!透過專注於最佳化頁面載入時間、可擴充性和提升使用者體驗的多項新增強功能,開發人員現在可以在同一個應用程式中使用 Blazor Server 和 Blazor WebAssembly,在執行階段自動將使用者從伺服器轉移到用戶端。得益於新的基於「Jiterpreter」的執行階段和新的內建元件,您的 .NET 程式碼在 WebAssembly 上的執行速度顯著加快。作為增強.NET 8 中整體驗證、授權和身分管理的一部分,Blazor 現在支援產生完整的基於 Blazor 的身分 UI。

img

7. NET MAUI – 提升效能、可靠性和開發人員體驗

.NET MAUI 提供單一專案系統和單一程式碼庫來構建 WinUI、Mac Catalyst、iOS 和 Android 應用程式。本機 AOT(實驗性)現在支援針對類似 iOS 的平台。適用於 .NET MAUI 的新 Visual Studio Code 擴充功能為您提供了開發跨平台 .NET 行動和桌面應用程式所需的工具。現在支援 Xcode 15 和 Android API 34,允許您瞄準最新版本的 iOS 和 Android。在效能、控制項和 UI 元素以及特定於平台的行為方面進行了大量的品質改進,例如桌面互動新增了更好的點選處理、鍵盤偵聽器等。

img

8. C# 12 功能 – 簡化語法以提高開發人員的生產力

C# 12 讓您的編碼體驗更加高效和愉快。現在,您可以使用簡單而優雅的語法在任何類別和結構中建立主建構函式。不再需要樣板程式碼來初始化您的欄位和屬性。使用簡潔且富有表現力的語法建立陣列、跨度和其他集合類型時會感到高興。對 lambda 運算式中的參數使用新的預設值。不再需要多載或 null 檢查來處理可選參數。您甚至可以使用 using alias 指令為任何類型新增別名,而不僅僅是命名類型!

8.1. 集合運算式

在 C# 12 之前,建立集合需要針對不同場景使用不同的語法。初始化List<int>int[]Span<int>所需不同的語法。以下是建立集合的幾種方法:

int[] x1 = new int[] { 1, 2, 3, 4 };
int[] x2 = Array.Empty<int>();
WriteByteArray(new[] { (byte)1, (byte)2, (byte)3 });
List<int> x4 = new() { 1, 2, 3, 4 };
Span<DateTime> dates = stackalloc DateTime[] { GetDate(0), GetDate(1) };
WriteByteSpan(stackalloc[] { (byte)1, (byte)2, (byte)3 });

8.2. 任何類別或結構上的主建構函式

C# 12 擴展了主建構函式以適用於所有類別和結構,而不僅僅是記錄。主建構函式允許在宣告類別時定義建構函式參數:

public class BankAccount(string accountID, string owner)
{
    public string AccountID { get; } = accountID;
    public string Owner { get; } = owner;

    public override string ToString() => $"Account ID: {AccountID}, Owner: {Owner}";
}

主建構函式參數最常見的用途是:

  • 作為 base() 建構函式呼叫的參數。
  • 初始化成員欄位或屬性。
  • 在實例成員中參考建構函式參數。
  • 刪除依賴注入中的樣板。

8.3. 別名任意類型

別名類型是從程式碼中刪除複雜類型簽名的便捷方法。using 從 C# 12 開始,其他類型在 alias 指令中有效。例如,這些別名在早期版本的 C# 中無效:

using intArray = int[]; // Array types.
using Point = (int x, int y);  // Tuple type
using unsafe ArrayPtr = int*;  // Pointer type (requires "unsafe")

8.4. 預設 lambda 參數

從 C# 12 開始,您可以在 lambda 運算式中宣告預設參數:

var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

8.5. 內嵌陣列

執行階段團隊和其他程式庫作者使用內嵌陣列來提高應用的效能。 內嵌陣列使開發人員能夠建立固定大小的 struct 類型陣列。 具有內嵌緩衝區的結構應提供類似於不安全的固定大小緩衝區的效能特徵。 你可能不會宣告自己的內嵌陣列,但當它們從執行階段 API 作為 System.SpanSystem.ReadOnlySpan 物件公開時,你將透明地使用這些陣列。

[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
    private int _element0;
}

它們的用法與任何其他陣列類似:

var buffer = new Buffer();
for (int i = 0; i < 10; i++)
{
    buffer[i] = i;
}

foreach (var i in buffer)
{
    Console.WriteLine(i);
}

區別在於編譯器可以利用有關內嵌陣列的已知資訊。 你可能會像使用任何其他陣列一樣使用內嵌陣列。 有關如何宣告內嵌陣列的詳細資訊,請參閱有關 struct 類型的語言參考。

9. 反射改進

.NET 5 中引入了函式指標,但當時未新增對反射的相應支援。 對函式指標使用 typeof 或反射時(例如分別使用 typeof(delegate*<void>()) FieldInfo.FieldType),傳回了 IntPtr。 從 .NET 8 開始,將改為傳回 System.Type 物件。 此類型提供對函式指標元資料的存取,包括呼叫慣例、傳回類型和參數。

新功能目前僅在 CoreCLR 執行階段和 MetadataLoadContext 中實作。已將新的 API 新增到 System.Type(例如 IsFunctionPointer)以及 System.Reflection.PropertyInfo、System.Reflection.FieldInfo 和 System.Reflection.ParameterInfo。 以下程式碼示範如何使用一些新 API 進行反射。

// Sample class that contains a function pointer field.
public unsafe class UClass
{
    public delegate* unmanaged[Cdecl, SuppressGCTransition]<in int, void> _fp;
}

// ...

FieldInfo fieldInfo = typeof(UClass).GetField(nameof(UClass._fp));

// Obtain the function pointer type from a field.
Type fpType = fieldInfo.FieldType;

// New methods to determine if a type is a function pointer.
Console.WriteLine($"IsFunctionPointer: {fpType.IsFunctionPointer}");
Console.WriteLine($"IsUnmanagedFunctionPointer: {fpType.IsUnmanagedFunctionPointer}");

// New methods to obtain the return and parameter types.
Console.WriteLine($"Return type: {fpType.GetFunctionPointerReturnType()}");

foreach (Type parameterType in fpType.GetFunctionPointerParameterTypes())
{
    Console.WriteLine($"Parameter type: {parameterType}");
}

// Access to custom modifiers and calling conventions requires a "modified type".
Type modifiedType = fieldInfo.GetModifiedFieldType();

// A modified type forwards most members to its underlying type.
Type normalType = modifiedType.UnderlyingSystemType;

// New method to obtain the calling conventions.
foreach (Type callConv in modifiedType.GetFunctionPointerCallingConventions())
{
    Console.WriteLine($"Calling convention: {callConv}");
}

// New method to obtain the custom modifiers.
foreach (Type modreq in modifiedType.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers())
{
    Console.WriteLine($"Required modifier for first parameter: {modreq}");
}

輸出:

IsFunctionPointer: True
IsUnmanagedFunctionPointer: True
Return type: System.Void
Parameter type: System.Int32&
Calling convention: System.Runtime.CompilerServices.CallConvSuppressGCTransition
Calling convention: System.Runtime.CompilerServices.CallConvCdecl
Required modifier for first parameter: System.Runtime.InteropServices.InAttribute

10. 設定繫結來源產生器

.NET 8 引入了一個來源產生器,用於在 ASP.NET Core 中提供 AOT 和適合剪裁的設定。 該產生器是現有的基於反射的實作的替代方法。

來源產生器探測 Configure(TOptions)、Bind 和 Get 呼叫來從中檢索類型資訊。 在專案中啟用產生器後,編譯器將隱式選擇產生的方法,而非預先存在的基於反射的框架實作。

無需變更原始碼即可使用產生器。 AOT Web 應用中預設啟用該產生器。 對於其他專案類型,來源產生器預設關閉,但你可透過在專案檔案中將 EnableConfigurationBindingGenerator 屬性設定為 true 來選擇使用它:

<PropertyGroup>
    <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
</PropertyGroup>

以下程式碼示範了呼叫繫結器的範例:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
IConfigurationSection section = builder.Configuration.GetSection("MyOptions");

// !! Configure call - to be replaced with source-gen'd implementation
builder.Services.Configure<MyOptions>(section);

// !! Get call - to be replaced with source-gen'd implementation
MyOptions options0 = section.Get<MyOptions>();

// !! Bind call - to be replaced with source-gen'd implementation
MyOptions options1 = new MyOptions();
section.Bind(options1);

WebApplication app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();

public class MyOptions
{
    public int A { get; set; }
    public string S { get; set; }
    public byte[] Data { get; set; }
    public Dictionary<string, string> Values { get; set; }
    public List<MyClass> Values2 { get; set; }
}

public class MyClass
{
    public int SomethingElse { get; set; }
}

11. 針對 Android 應用的 AOT 編譯

為了減小應用大小,面向 Android 的 .NET 和 .NET MAUI 應用在發佈模式下構建時使用分析的前置 (AOT) 編譯模式。 與常規 AOT 編譯相比,分析的 AOT 編譯所影響的方法更少。 .NET 8 引入了 <AndroidStripILAfterAOT> 屬性,你可使用它進一步對 Android 應用進行 AOT 編譯,從而更進一步減少應用大小。

<PropertyGroup>
  <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
</PropertyGroup>

預設情況下,將 AndroidStripILAfterAOT 設定為 true 會替代預設的 AndroidEnableProfiledAot 設定,從而允許剪裁已 AOT 編譯的(幾乎)所有方法。 還可透過將兩個屬性都明確設定為 true 來結合使用分析的 AOT 和 IL 條帶化:

<PropertyGroup>
  <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
  <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>

12.程式碼分析

.NET 8 包括幾個新的程式碼分析器和修復程式,可協助驗證是否正確且高效地使用 .NET 程式庫 API。 下表總結了新的分析器。

規則 ID 類別 說明
CA1856 效能 未在參數上正確應用 ConstantExpectedAttribute 屬性時觸發。
CA1857 效能 當參數使用 ConstantExpectedAttribute 新增註釋但提供的參數不是常數時觸發。
CA1858 效能 若要確定字串是否以給定前置詞開頭,最好呼叫 String.StartsWith,而不是呼叫 String.IndexOf,然後將結果與零進行比較。
CA1859 效能 此規則建議盡可能將特定區域變數、欄位、屬性、方法參數和方法返回類型從介面或抽象類型升級到具體類型。 使用具體類型可產生更高品質的程式碼。
CA1860 效能 若要確定集合類型是否具有任何元素,最好使用 Length、Count 或 IsEmpty,而不是呼叫 Enumerable.Any
CA1861 效能 重複呼叫時,不會重複使用作為參數傳遞的常數陣列,這意味著每次都會建立一個新陣列。 若要提高效能,請考慮將陣列提取到靜態唯讀欄位。
CA1865-CA1867 效能 對於單一字串,char 多載的效能更好。
CA2021 可靠性 Enumerable.Cast(IEnumerable)Enumerable.OfType(IEnumerable) 需要相容的類型才能正常執行。 泛型類型不支援擴大轉換和使用者定義的轉換。
CA1510-CA1513 可維護性 在構造新的例外實例方面,引發協助程式比 if 區塊更簡單、更高效。 這四個分析器是為以下例外情況建立的:ArgumentNullExceptionArgumentExceptionArgumentOutOfRangeExceptionObjectDisposedException

13. .NET Core 程式庫

13.1. 時間抽象

新的 TimeProvider 類別和 ITimer 介面新增了時間抽象功能,讓你可以在此測試案例中模擬時間。 此外,還可以使用時間抽象,透過 Task.DelayTask.WaitAsync 來模擬依賴於時間進度的 Task 操作。 時間抽象支援以下基本時間操作:

  • 檢索本地和 UTC 時間
  • 獲取用於測量效能的時間戳記
  • 建立計時器

以下程式碼片段示範了一些使用情況範例。

// Get system time.
DateTimeOffset utcNow = TimeProvider.System.GetUtcNow();
DateTimeOffset localNow = TimeProvider.System.GetLocalNow();

// Create a time provider that works with a
// time zone that's different than the local time zone.
private class ZonedTimeProvider : TimeProvider
{
    private TimeZoneInfo _zoneInfo;

    public ZonedTimeProvider(TimeZoneInfo zoneInfo) : base()
    {
        _zoneInfo = zoneInfo ?? TimeZoneInfo.Local;
    }

    public override TimeZoneInfo LocalTimeZone => _zoneInfo;

    public static TimeProvider FromLocalTimeZone(TimeZoneInfo zoneInfo) =>
        new ZonedTimeProvider(zoneInfo);
}

// Create a timer using a time provider.
ITimer timer = timeProvider.CreateTimer(callBack, state, delay, Timeout.InfiniteTimeSpan);

// Measure a period using the system time provider.
long providerTimestamp1 = TimeProvider.System.GetTimestamp();
long providerTimestamp2 = TimeProvider.System.GetTimestamp();

var period = GetElapsedTime(providerTimestamp1, providerTimestamp2);

13.2. UTF8 改進

如果要啟用將類型的類似字串的表示形式寫出到目標範圍,請在類型上實作新的 IUtf8SpanFormattable 介面。 此新介面與 ISpanFormattable 密切相關,但面向 UTF8 和 Span<byte>,而不是 UTF16 和 Span<char>

IUtf8SpanFormattable 已在所有基本類型(以及其他)上實作,無論是面向 string、Span<char> 還是 Span<byte>,其共享邏輯完全一致。 它完全支援所有格式(包括新的「B」二進位指定符)和所有地區設定。 這意味著現在可以從 Byte、Complex、Char、DateOnly、DateTime、DateTimeOffset、Decimal、Double、Guid、Half、IPAddress、IPNetwork、Int16、Int32、Int64、Int128、IntPtr、NFloat、SByte、Single、Rune、TimeOnly、TimeSpan、UInt16、UInt32、UInt64、UInt128、UIntPtr 和 Version 直接格式化為 UTF8。

新的 Utf8.TryWrite 方法向現有 MemoryExtensions.TryWrite 方法(基於 UTF16)提供基於 UTF8 的對應方法。 可以使用內插字串語法將複雜運算式直接格式化為 UTF8 位元組範圍,例如:

static bool FormatHexVersion(
    short major,
    short minor,
    short build,
    short revision,
    Span<byte> utf8Bytes,
    out int bytesWritten) =>
    Utf8.TryWrite(
        utf8Bytes,
        CultureInfo.InvariantCulture,
        $"{major:X4}.{minor:X4}.{build:X4}.{revision:X4}",
        out bytesWritten);

13.3. 加密

.NET 8 新增了對 SHA-3 雜湊基元的支援。 (目前,具有 OpenSSL 1.1.1 或更高版本和 Windows 11 Build 25324 或更高版本的 Linux 支援 SHA-3。)可在其中使用 SHA-2 的 API 現在提供對 SHA-3 的補充。 對於雜湊,這包括 SHA3_256、SHA3_384 和 SHA3_512;對於 HMAC,這包括 HMACSHA3_256、HMACSHA3_384 和 HMACSHA3_512;對於其中可設定演算法的雜湊,這包括 HashAlgorithmName.SHA3_256、HashAlgorithmName.SHA3_384 和 HashAlgorithmName.SHA3_512;對於 RSA OAEP 加密,這包括 RSAEncryptionPadding.OaepSHA3_256、RSAEncryptionPadding.OaepSHA3_384 和 RSAEncryptionPadding.OaepSHA3_512。

以下範例示範如何使用 API(包括 SHA3_256.IsSupported 屬性)來確定平台是否支援 SHA-3。

// Hashing example
if (SHA3_256.IsSupported)
{
    byte[] hash = SHA3_256.HashData(dataToHash);
}
else
{
    // ...
}

// Signing example
if (SHA3_256.IsSupported)
{
     using ECDsa ec = ECDsa.Create(ECCurve.NamedCurves.nistP256);
     byte[] signature = ec.SignData(dataToBeSigned, HashAlgorithmName.SHA3_256);
}
else
{
    // ...
}

13.4. 基於串流的 ZipFile 方法

.NET 8 包含 ZipFile.CreateFromDirectory 的新多載,透過它可以收集目錄中包含的所有檔案並壓縮這些檔案,然後將產生的 zip 檔案儲存到提供的串流中。 同樣,透過新的 ZipFile.ExtractToDirectory 多載,可提供包含壓縮檔案的串流,並將其內容提取到檔案系統中。 下面是新的多載:

namespace System.IO.Compression;

public static partial class ZipFile
{
    public static void CreateFromDirectory(string sourceDirectoryName, Stream destination);
    public static void CreateFromDirectory(string sourceDirectoryName, Stream destination, CompressionLevel compressionLevel, bool includeBaseDirectory);
    public static void CreateFromDirectory(string sourceDirectoryName, Stream destination, CompressionLevel compressionLevel, bool includeBaseDirectory, Encoding? entryNameEncoding);

    public static void ExtractToDirectory(Stream source, string destinationDirectoryName) { }
    public static void ExtractToDirectory(Stream source, string destinationDirectoryName, bool overwriteFiles) { }
    public static void ExtractToDirectory(Stream source, string destinationDirectoryName, Encoding? entryNameEncoding) { }
    public static void ExtractToDirectory(Stream source, string destinationDirectoryName, Encoding? entryNameEncoding, bool overwriteFiles) { }
}

GrapeCity Documents for Excel (簡稱 GcExcel)是一款藉助是一款基於 .NET 和 .NET Core 平台的服務端高效能表格元件,無需依賴 Office、NPOI 或第三方應用軟體, 在前端展示表格資料,在服務端批次建立、載入、編輯、列印、匯入/匯出 Excel 文件,為您開發的應用程式提供線上文件的前後端資料同步、線上填報與服務端批次匯出與列印。

ActiveReports是一款專注於 .NET 和 .NET Core 平台的報表控制項。透過拖曳式報表設計器,可以快速地設計 Excel 表格、Word 文件、圖表、資料篩選、資料鑽取、精準套打等類型報表,全面滿足 WinForm、ASP.NET、ASP.NET MVC、WPF 平台中各種報表的開發需要。同時,透過豐富的 API 可以靈活的實現報表建立、載入和執行階段的個人化自定義需求。

Wyn 商業智慧是基於葡萄城 20 多年資料分析技術積累打造的全新一代嵌入式 BI 產品,旨在提供可與應用系統深度整合的資料分析功能,能夠與企業現有業務系統 OA, ERP,MES,CRM 等應用系統深度整合,整合、分析多個業務系統的資料,自助式分析業務資料、即時分析決策,全面提升企業競爭力。

Spread .NET是一個功能、佈局與 Excel 高度類似的 .NET 表格控制項,可全面滿足 WinForm、ASP.NET、XAML 和 WinRT 等平台下表格資料處理、資料視覺化開發需求。Spread .NET 支援 462 種 Excel 公式,提供可嵌入系統的類 Excel 設計器和全面開放的 API,為 .NET 開發人員構建企業級表格應用程式提供更加專業的選擇。

參考資料:

https://learn.microsoft.com/zh-tw/dotnet/core/whats-new/dotnet-8#networking

擴展連結:

如何使用 Blazor 框架在前端瀏覽器中匯入/匯出 Excel XLSX

如何在.NET 電子表格應用程式中建立流程圖

如何將即時數據顯示在前端電子表格中


本文是由葡萄城技術開發團隊發佈,轉載請註明出處:葡萄城官網

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2026/2/7

AOT使用經驗總結

從專案建立伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 AOT 發布測試。

繼續閱讀