Novinky v .NET 9

Seznamte se s novými funkcemi v .NET 9 a najděte odkazy na další dokumentaci.

.NET 9, následník .NET 8, má zvláštní zaměření na aplikace nativní pro cloud a výkon. Bude podporován po dobu 18 měsíců jako verze standardní podpory (STS). .NET 9 si můžete stáhnout zde.

Nový pro .NET 9, technický tým publikuje aktualizace .NET 9 Preview na diskuzích Na GitHubu. Je to skvělé místo, kde můžete klást otázky a poskytovat zpětnou vazbu k vydání verze.

Tento článek byl aktualizován pro .NET 9 Preview 2. Následující části popisují aktualizace základních knihoven .NET v .NET 9.

Modul runtime .NET

Serializace

V System.Text.Jsonrozhraní .NET 9 jsou nové možnosti serializace JSON a nového singletonu, který usnadňuje serializaci pomocí výchozích hodnot webu.

Možnosti odsazení

JsonSerializerOptions obsahuje nové vlastnosti, které umožňují přizpůsobit odsazení a velikost odsazení zapsaného JSON.

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    IndentCharacter = '\t',
    IndentSize = 2,
};

string json = JsonSerializer.Serialize(
    new { Value = 1 },
    options
    );
Console.WriteLine(json);
//{
//                "Value": 1
//}

Výchozí webové možnosti

Pokud chcete serializovat s výchozími možnostmi , které ASP.NET Core používá pro webové aplikace, použijte nový JsonSerializerOptions.Web singleton.

string webJson = JsonSerializer.Serialize(
    new { SomeValue = 42 },
    JsonSerializerOptions.Web // Defaults to camelCase naming policy.
    );
Console.WriteLine(webJson);
// {"someValue":42}

LINQ

Byly zavedeny nové metody CountByAggregateBy . Tyto metody umožňují agregovat stav podle klíče, aniž by bylo nutné přidělovat přechodné seskupení prostřednictvím GroupBy.

CountBy umožňuje rychle vypočítat frekvenci jednotlivých klíčů. Následující příklad najde slovo, které se vyskytuje nejčastěji v textovém řetězci.

string sourceText = """
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Sed non risus. Suspendisse lectus tortor, dignissim sit amet, 
    adipiscing nec, ultricies sed, dolor. Cras elementum ultrices amet diam.
""";

// Find the most frequent word in the text.
KeyValuePair<string, int> mostFrequentWord = sourceText
    .Split(new char[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries)
    .Select(word => word.ToLowerInvariant())
    .CountBy(word => word)
    .MaxBy(pair => pair.Value);

Console.WriteLine(mostFrequentWord.Key); // amet

AggregateBy umožňuje implementovat více obecných pracovních postupů. Následující příklad ukazuje, jak můžete vypočítat skóre, která jsou přidružena k danému klíči.

(string id, int score)[] data =
    [
        ("0", 42),
        ("1", 5),
        ("2", 4),
        ("1", 10),
        ("0", 25),
    ];

var aggregatedData =
    data.AggregateBy(
        keySelector: entry => entry.id,
        seed: 0,
        (totalScore, curr) => totalScore + curr.score
        );

foreach (var item in aggregatedData)
{
    Console.WriteLine(item);
}
//(0, 67)
//(1, 15)
//(2, 4)

Index<TSource>(IEnumerable<TSource>) umožňuje rychle extrahovat implicitní index výčtu. Teď můžete napsat kód, například následující fragment kódu, který automaticky indexuje položky v kolekci.

IEnumerable<string> lines2 = File.ReadAllLines("output.txt");
foreach ((int index, string line) in lines2.Index())
{
    Console.WriteLine($"Line number: {index + 1}, Line: {line}");
}

Kolekce

Typ PriorityQueue<TElement,TPriority> kolekce v System.Collections.Generic oboru názvů obsahuje novou Remove(TElement, TElement, TPriority, IEqualityComparer<TElement>) metodu, kterou můžete použít k aktualizaci priority položky ve frontě.

Metoda PriorityQueue.Remove()

.NET 6 představil kolekci PriorityQueue<TElement,TPriority> , která poskytuje jednoduchou a rychlou implementaci haldy pole. Jedním z obecných problémů s haldami polí je, že nepodporují aktualizace priority, což z nich znemožňuje použití v algoritmech, jako jsou varianty algoritmu Dijkstra.

I když v existující kolekci není možné implementovat efektivní aktualizace priority $O(\log n)$, nová PriorityQueue<TElement,TPriority>.Remove(TElement, TElement, TPriority, IEqualityComparer<TElement>) metoda umožňuje emulovat aktualizace priority (i když v době $O(n)$):

public static void UpdatePriority<TElement, TPriority>(
    this PriorityQueue<TElement, TPriority> queue,
    TElement element,
    TPriority priority
    )
{
    // Scan the heap for entries matching the current element.
    queue.Remove(element, out _, out _);
    // Re-insert the entry with the new priority.
    queue.Enqueue(element, priority);
}

Tato metoda odblokuje uživatele, kteří chtějí implementovat algoritmy grafu v kontextech, kde asymptotický výkon není blokátorem. (Tyto kontexty zahrnují vzdělávání a vytváření prototypů.) Tady je například implementace toy implementace algoritmu Dijkstra, která používá nové rozhraní API.

Kryptografie

Pro kryptografii .NET 9 přidá novou metodu hash s jedním snímkem na CryptographicOperations typ. Přidá také nové třídy, které používají algoritmus KMAC.

Metoda CryptographicOperations.HashData()

.NET zahrnuje několik statických implementací hashových funkcí a souvisejících funkcí. Tato rozhraní API zahrnují SHA256.HashData a HMACSHA256.HashData. Jednostřelová rozhraní API je vhodnější použít, protože poskytují nejlepší možný výkon a snižují nebo eliminují přidělení.

Pokud vývojář chce poskytnout rozhraní API, které podporuje hashování, ve kterém volající definuje, který hashovací algoritmus se má použít, obvykle se provádí přijetím argumentu HashAlgorithmName . Použití takového vzoru s jednostřelovými rozhraními API by však vyžadovalo přepnutí na všechny možné možnosti HashAlgorithmName a následné použití příslušné metody. Aby bylo možné tento problém vyřešit, rozhraní .NET 9 zavádí CryptographicOperations.HashData rozhraní API. Toto rozhraní API umožňuje vytvořit hodnotu hash nebo HMAC přes vstup jako jeden snímek, ve kterém HashAlgorithmNameje použitý algoritmus určen hodnotou .

static void HashAndProcessData(HashAlgorithmName hashAlgorithmName, byte[] data)
{
    byte[] hash = CryptographicOperations.HashData(hashAlgorithmName, data);
    ProcessHash(hash);
}

Algoritmus KMAC

.NET 9 poskytuje algoritmus KMAC určený službou NIST SP-800-185. KECCAK Message Authentication Code (KMAC) je pseudonáhodná funkce a klíčovaná hash funkce založená na KECCAK.

Následující nové třídy používají algoritmus KMAC. Pomocí instancí můžete shromáždit data k vytvoření mac nebo použít statickou HashData metodu pro jednorázový vstup.

KMAC je k dispozici v Linuxu s OpenSSL 3.0 nebo novějším a ve Windows 11 Build 26016 nebo novějším. Statickou IsSupported vlastnost můžete použít k určení, jestli platforma podporuje požadovaný algoritmus.

if (Kmac128.IsSupported)
{
    byte[] key = GetKmacKey();
    byte[] input = GetInputToMac();
    byte[] mac = Kmac128.HashData(key, input, outputLength: 32);
}
else
{
    // Handle scenario where KMAC isn't available.
}

Reflexe

Ve verzích .NET Core a .NET 5-8 byla podpora sestavení a generování metadat reflexe pro dynamicky vytvořené typy omezena na spustitelnou AssemblyBuilder. Nedostatek podpory pro ukládání sestavení byl často překážkou pro zákazníky, kteří migrují z rozhraní .NET Framework na .NET. .NET 9 přidá veřejná rozhraní API pro AssemblyBuilder uložení generovaného sestavení.

Nová trvalá AssemblyBuilder implementace je nezávislá na modulu runtime a platformě. K vytvoření trvalé AssemblyBuilder instance použijte nové AssemblyBuilder.DefinePersistedAssembly rozhraní API. AssemblyBuilder.DefineDynamicAssembly Existující rozhraní API přijímá název sestavení a volitelné vlastní atributy. Pokud chcete použít nové rozhraní API, předejte základní sestavení, System.Private.CoreLibkteré se používá pro odkazování na základní typy modulu runtime. Neexistuje žádná možnost pro AssemblyBuilderAccess. A prozatím trvalá AssemblyBuilder implementace podporuje pouze ukládání, ne spuštění. Po vytvoření instance trvalé AssemblyBuilder, následné kroky pro definování modulu, typu, metody nebo výčtu, psaní IL a všech ostatních použití zůstávají beze změny. To znamená, že pro uložení sestavení můžete použít existující System.Reflection.Emit kód tak, jak je. Následující kód znázorňuje příklad.

public void CreateAndSaveAssembly(string assemblyPath)
{
    AssemblyBuilder ab = AssemblyBuilder.DefinePersistedAssembly(
        new AssemblyName("MyAssembly"),
        typeof(object).Assembly
        );
    TypeBuilder tb = ab.DefineDynamicModule("MyModule")
        .DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);

    MethodBuilder mb = tb.DefineMethod(
        "SumMethod",
        MethodAttributes.Public | MethodAttributes.Static,
        typeof(int), [typeof(int), typeof(int)]
        );
    ILGenerator il = mb.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    tb.CreateType();
    ab.Save(assemblyPath); // or could save to a Stream
}

public void UseAssembly(string assemblyPath)
{
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    Type type = assembly.GetType("MyType");
    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, [5, 10]));
}

Výkon

.NET 9 zahrnuje vylepšení 64bitového kompilátoru JIT zaměřeného na zlepšení výkonu aplikace. Mezi tato vylepšení kompilátoru patří:

Vektorizace Arm64 je další novou funkcí modulu runtime.

Optimalizace smyček

Vylepšení generování kódu pro smyčky je prioritou pro .NET 9 a 64bitový kompilátor obsahuje novou optimalizaci označovanou jako rozšiřující indukční proměnná (IV).

Iv je proměnná, jejíž hodnota se mění jako obsahující smyčka iteruje. V následující for smyčce i je IV: for (int i = 0; i < 10; i++). Pokud kompilátor dokáže analyzovat, jak se hodnota IV vyvíjí přes iterace smyčky, může vytvořit výkonnější kód pro související výrazy.

Podívejte se na následující příklad, který prochází polem:

static int Sum(int[] arr)
{
    int sum = 0;
    for (int i = 0; i < arr.Length; i++)
    {
        sum += arr[i];
    }

    return sum;
}

Proměnná iindexu má velikost 4 bajty. Na úrovni sestavení se 64bitové registry obvykle používají k uchování indexů pole na platformě x64 a v předchozích verzích .NET kompilátor vygeneroval kód, který byl pro přístup k poli rozšířen i na 8 bajtů, ale pokračoval v zacházení i jako se 4 bajtovým celočíselnou hodnotou jinde. Rozšíření i na 8 bajtů však vyžaduje další instrukce pro x64. S rozšířením IV se 64bitový kompilátor JIT nyní rozšiřuje i na 8 bajtů v celé smyčce a vynechá nulové rozšíření. Smyčky nad poli jsou velmi běžné a výhody tohoto odebrání instrukcí se rychle sčítají.

Vylepšení vkládání nativních AOT

Jeden z . Cílem rozhraní NET pro vložený 64bitový kompilátor JIT je odebrat co nejvíce omezení, která blokují inlinování metody. .NET 9 umožňuje inlinovat přístup k místním statickým objektům s vlákny ve Windows x64, Linuxu x64 a Linuxu Arm64.

U static členů třídy existuje přesně jedna instance člena ve všech instancích třídy, které člena "sdílejí". Pokud je hodnota člena static jedinečná pro každé vlákno, může zvýšit výkon, protože eliminuje potřebu souběžnosti pro bezpečný přístup ke členu static z jeho obsahujícího vlákna.

Dříve byl přístup k místním statickým objektům s vlákny v nativních programech kompilovaných pomocí AOT vyžadován 64bitový kompilátor JIT k vygenerování volání do modulu runtime, aby získal základní adresu místního úložiště vlákna. Kompilátor teď může tato volání vkládat, což vede k mnohem menšímu počtu instrukcí pro přístup k těmto datům.

Vylepšení PGO: Kontroly typů a přetypování

Technologie .NET 8 ve výchozím nastavení povolila dynamickou optimalizaci s asistencí profilu (PGO). NET 9 rozšiřuje 64bitovou implementaci PGO kompilátoru JIT, aby profiloval více vzorů kódu. Po povolení vrstvené kompilace už 64bitový kompilátor JIT vloží instrumentaci do programu, aby profiloval jeho chování. Při rekompilování s optimalizací kompilátor využívá profil vytvořený za běhu k rozhodování specifické pro aktuální spuštění programu. V .NET 9 používá 64bitový kompilátor JIT data PGO ke zlepšení výkonu kontrol typů.

Určení typu objektu vyžaduje volání modulu runtime, které se dodává s trestem výkonu. Když je potřeba zkontrolovat typ objektu, 64bitový kompilátor JIT toto volání vygeneruje kvůli správnosti (kompilátory obvykle nemohou vyloučit žádné možnosti, i když se zdají být nepravděpodobné). Pokud však data PGO naznačují, že objekt bude pravděpodobně určitým typem, kompilátor JIT 64bitové verze teď generuje rychlou cestu , která levně kontroluje tento typ a vrací se zpět na pomalou cestu volání do modulu runtime pouze v případě potřeby.

Vektorizace Arm64 v knihovnách .NET

Nová EncodeToUtf8 implementace využívá 64bitovou možnost kompilátoru JIT generovat pokyny pro načítání a ukládání s více registracemi v Arm64. Toto chování umožňuje programům zpracovávat větší bloky dat s menším počtem instrukcí. Aplikace .NET napříč různými doménami by měly vidět vylepšení propustnosti hardwaru Arm64, který tyto funkce podporuje. Některé srovnávací testy zkrátily dobu provádění o více než polovinu.

.NET SDK

Testování částí

Tato část popisuje aktualizace testování částí v .NET 9: paralelní spouštění testů a výstup testu protokolovacího modulu terminálu.

Paralelní spouštění testů

V .NET 9 dotnet test je plně integrovaná s nástrojem MSBuild. Vzhledem k tomu, že NÁSTROJ MSBuild podporuje paralelní sestavování, můžete paralelně spouštět testy pro stejný projekt napříč různými cílovými architekturami. Ve výchozím nastavení msBuild omezuje počet paralelních procesů na počet procesorů v počítači. Můžete také nastavit vlastní limit pomocí přepínače -maxcpucount . Pokud chcete zrušit paralelismus, nastavte TestTfmsInParallel vlastnost MSBuild na falsehodnotu .

Zobrazení testu protokolovacího nástroje terminálu

Generování sestav dotnet test výsledků testu je nyní podporováno přímo v protokolovacím nástroji terminálu MSBuild. Když testy běží (zobrazí se název spuštěného testu), a po dokončení testů se zobrazí více funkčních sestav testů (všechny chyby testů se vykreslují lepším způsobem).

Další informace o protokolovacím nástroji terminálu naleznete v tématu dotnet build options.

Přechod k nástrojům .NET vpřed

Nástroje .NET jsou aplikace závislé na architektuře, které můžete nainstalovat globálně nebo místně, a pak spouštět pomocí sady .NET SDK a nainstalované moduly runtime .NET. Tyto nástroje, jako jsou všechny aplikace .NET, cílí na konkrétní hlavní verzi .NET. Ve výchozím nastavení se aplikace nespouštějí na novějších verzích .NET. Autoři nástrojů se mohli přihlásit ke spouštění nástrojů v novějších verzích modulu runtime .NET nastavením RollForward vlastnosti MSBuild. Ne všechny nástroje to ale dělají.

Nová možnost, která dotnet tool install umožňuje uživatelům rozhodnout, jak se mají spouštět nástroje .NET. Při instalaci nástroje prostřednictvím dotnet tool install, nebo při spuštění nástroje prostřednictvím dotnet tool run <toolname>, můžete zadat nový příznak volal --allow-roll-forward. Tato možnost nakonfiguruje nástroj s režimem roll-forward Major. Tento režim umožňuje nástroj spustit na novější hlavní verzi .NET, pokud odpovídající verze .NET není k dispozici. Tato funkce pomáhá dřívějším uživatelům používat nástroje .NET, aniž by autoři nástrojů museli měnit jakýkoli kód.

Viz také