Bagikan melalui


Apa yang baru di .NET 9

Pelajari tentang fitur baru di .NET 9 dan temukan tautan ke dokumentasi lebih lanjut.

.NET 9, penerus .NET 8, memiliki fokus khusus pada aplikasi dan performa cloud-native. Ini akan didukung selama 18 bulan sebagai rilis dukungan jangka standar (STS). Anda dapat mengunduh .NET 9 di sini.

Baru untuk .NET 9, tim teknik memposting pembaruan pratinjau .NET 9 di Diskusi GitHub. Itu adalah tempat yang bagus untuk mengajukan pertanyaan dan memberikan umpan balik tentang rilis.

Artikel ini telah diperbarui untuk Pratinjau .NET 9 2. Bagian berikut menjelaskan pembaruan untuk pustaka .NET inti di .NET 9.

Runtime .NET

Serialisasi

Dalam System.Text.Json, .NET 9 memiliki opsi baru untuk menserialisasikan JSON dan singleton baru yang membuatnya lebih mudah untuk diserialisasikan menggunakan default web.

Opsi indentasi

JsonSerializerOptions termasuk properti baru yang memungkinkan Anda menyesuaikan karakter indentasi dan ukuran indentasi JSON tertulis.

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

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

Opsi web default

Jika Anda ingin membuat serialisasi dengan opsi default yang ASP.NET core gunakan untuk aplikasi web, gunakan singleton baru JsonSerializerOptions.Web .

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

LINQ

CountBy Metode baru dan AggregateBy telah diperkenalkan. Metode ini memungkinkan untuk mengagregasi status dengan kunci tanpa perlu mengalokasikan pengelompokan menengah melalui GroupBy.

CountBy memungkinkan Anda menghitung frekuensi setiap kunci dengan cepat. Contoh berikut menemukan kata yang paling sering terjadi dalam string teks.

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 memungkinkan Anda menerapkan alur kerja yang lebih tujuan umum. Contoh berikut menunjukkan bagaimana Anda dapat menghitung skor yang terkait dengan kunci tertentu.

(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>) memungkinkan untuk dengan cepat mengekstrak indeks implisit dari enumerable. Sekarang Anda dapat menulis kode seperti cuplikan berikut untuk mengindeks item secara otomatis dalam koleksi.

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

Koleksi

Jenis PriorityQueue<TElement,TPriority> koleksi di System.Collections.Generic namespace menyertakan metode baru Remove(TElement, TElement, TPriority, IEqualityComparer<TElement>) yang dapat Anda gunakan untuk memperbarui prioritas item dalam antrean.

Metode PriorityQueue.Remove()

.NET 6 memperkenalkan PriorityQueue<TElement,TPriority> koleksi, yang menyediakan implementasi array-heap yang sederhana dan cepat. Salah satu masalah dengan timbunan array secara umum adalah bahwa mereka tidak mendukung pembaruan prioritas, yang membuatnya dilarang untuk digunakan dalam algoritma seperti variasi algoritma Dijkstra.

Meskipun tidak mungkin untuk menerapkan pembaruan prioritas $O(\log n)$ yang efisien dalam koleksi yang ada, metode baru PriorityQueue<TElement,TPriority>.Remove(TElement, TElement, TPriority, IEqualityComparer<TElement>) memungkinkan untuk meniru pembaruan prioritas (meskipun pada $O(n)$ waktu):

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

Metode ini membuka blokir pengguna yang ingin menerapkan algoritma grafik dalam konteks di mana performa asimptotik bukan pemblokir. (Konteks tersebut termasuk pendidikan dan prototipe.) Misalnya, berikut adalah implementasi mainan algoritma Dijkstra yang menggunakan API baru.

Kriptografi

Untuk kriptografi, .NET 9 menambahkan metode hash satu bidikan baru pada jenis .CryptographicOperations Ini juga menambahkan kelas baru yang menggunakan algoritma KMAC.

Metode CryptographicOperations.HashData()

.NET mencakup beberapa implementasi statis "satu bidikan" fungsi hash dan fungsi terkait. API ini mencakup SHA256.HashData dan HMACSHA256.HashData. API satu bidikan lebih baik digunakan karena dapat memberikan performa terbaik dan mengurangi atau menghilangkan alokasi.

Jika pengembang ingin menyediakan API yang mendukung hashing di mana pemanggil menentukan algoritma hash mana yang akan digunakan, biasanya dilakukan dengan menerima HashAlgorithmName argumen. Namun, menggunakan pola tersebut dengan API satu bidikan akan memerlukan pengalihan atas setiap kemungkinan HashAlgorithmName dan kemudian menggunakan metode yang sesuai. Untuk mengatasi masalah tersebut, .NET 9 memperkenalkan CryptographicOperations.HashData API. API ini memungkinkan Anda menghasilkan hash atau HMAC melalui input sebagai satu bidikan di mana algoritma yang digunakan ditentukan oleh HashAlgorithmName.

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

Algoritma KMAC

.NET 9 menyediakan algoritma KMAC seperti yang ditentukan oleh NIST SP-800-185. KECCAK Message Authentication Code (KMAC) adalah fungsi pseudorandom dan fungsi hash kunci berdasarkan KECCAK.

Kelas baru berikut menggunakan algoritma KMAC. Gunakan instans untuk mengakumulasi data untuk menghasilkan MAC, atau gunakan metode statis HashData untuk satu bidikan melalui satu input.

KMAC tersedia di Linux dengan OpenSSL 3.0 atau yang lebih baru, dan pada Windows 11 Build 26016 atau yang lebih baru. Anda dapat menggunakan properti statis IsSupported untuk menentukan apakah platform mendukung algoritma yang diinginkan.

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

Refleksi

Dalam versi .NET Core dan .NET 5-8, dukungan untuk membangun metadata assembly dan memancarkan refleksi untuk jenis yang dibuat secara dinamis terbatas pada yang dapat AssemblyBuilderdijalankan . Kurangnya dukungan untuk menyimpan rakitan sering kali menjadi pemblokir bagi pelanggan yang bermigrasi dari .NET Framework ke .NET. .NET 9 menambahkan API publik untuk AssemblyBuilder menyimpan rakitan yang dipancarkan.

Implementasi baru yang AssemblyBuilder bertahan adalah runtime dan platform independen. Untuk membuat instans yang AssemblyBuilder bertahan, gunakan API baru AssemblyBuilder.DefinePersistedAssembly . API yang AssemblyBuilder.DefineDynamicAssembly ada menerima nama rakitan dan atribut kustom opsional. Untuk menggunakan API baru, lewati perakitan inti, System.Private.CoreLib, yang digunakan untuk mereferensikan jenis runtime dasar. Tidak ada opsi untuk AssemblyBuilderAccess. Dan untuk saat ini, implementasi yang bertahan AssemblyBuilder hanya mendukung penghematan, tidak berjalan. Setelah Anda membuat instans yang bertahan AssemblyBuilder, langkah-langkah berikutnya untuk menentukan modul, jenis, metode, atau enum, menulis IL, dan semua penggunaan lainnya tetap tidak berubah. Itu berarti Anda dapat menggunakan kode yang ada System.Reflection.Emit apa adanya untuk menyimpan rakitan. Kode berikut menunjukkan contoh.

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

Performa

.NET 9 mencakup peningkatan pada kompilator JIT 64-bit yang bertujuan untuk meningkatkan performa aplikasi. Penyempurnaan kompilator ini meliputi:

Vektorisasi Arm64 adalah fitur baru lain dari runtime.

Pengoptimalan perulangan

Meningkatkan pembuatan kode untuk perulangan adalah prioritas untuk .NET 9, dan kompiler 64-bit memiliki pengoptimalan baru yang disebut pelesiran variabel induksi (IV).

IV adalah variabel yang nilainya berubah saat perulangan yang berisi berulang. Dalam perulangan berikut for , i adalah IV: for (int i = 0; i < 10; i++). Jika kompilator dapat menganalisis bagaimana nilai IV berevolusi atas iterasi perulangannya, ia dapat menghasilkan kode yang lebih berkinerja untuk ekspresi terkait.

Pertimbangkan contoh berikut yang berulang melalui array:

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

    return sum;
}

Variabel indeks, i, berukuran 4 byte. Pada tingkat rakitan, register 64-bit biasanya digunakan untuk menyimpan indeks array pada x64, dan dalam versi .NET sebelumnya, pengkompilasi menghasilkan kode yang diperluas i nol hingga 8 byte untuk akses array, tetapi terus diperlakukan i sebagai bilangan bulat 4-byte di tempat lain. Namun, memperluas i hingga 8 byte memerlukan instruksi tambahan pada x64. Dengan melebarnya IV, pengkompilasi JIT 64-bit sekarang melebar i menjadi 8 byte di seluruh perulangan, menghilangkan ekstensi nol. Perulangan di atas array sangat umum, dan manfaat penghapusan instruksi ini dengan cepat ditambahkan.

Peningkatan inlining untuk AOT Asli

Salah satu dari . Tujuan NET untuk inliner kompilator JIT 64-bit adalah untuk menghapus pembatasan sebanyak mungkin yang memblokir metode agar tidak sebaris mungkin. .NET 9 memungkinkan inlining akses ke statis thread-local pada Windows x64, Linux x64, dan Linux Arm64.

Untuk static anggota kelas, tepat satu instans anggota ada di semua instans kelas, yang "berbagi" anggota. Jika nilai static anggota unik untuk setiap utas, membuat nilai thread-local dapat meningkatkan performa, karena menghilangkan kebutuhan akan primitif konkurensi untuk mengakses static anggota dengan aman dari utas yang berisi.

Sebelumnya, akses ke statis thread-local dalam program yang dikompilasi AOT Asli mengharuskan pengkompilasi JIT 64-bit untuk memancarkan panggilan ke runtime untuk mendapatkan alamat dasar penyimpanan thread-local. Sekarang, pengkompilasi dapat menginline panggilan ini, menghasilkan instruksi yang jauh lebih sedikit untuk mengakses data ini.

Peningkatan PGO: Mengetik pemeriksaan dan transmisi

Pengoptimalan yang dipandu profil dinamis (PGO) yang diaktifkan .NET 8 secara default. NET 9 memperluas implementasi PGO kompilator JIT 64-bit untuk memprofilkan lebih banyak pola kode. Ketika kompilasi berjenjang diaktifkan, pengkompilasi JIT 64-bit sudah menyisipkan instrumentasi ke dalam program Anda untuk memprofilkan perilakunya. Ketika dikompilasi ulang dengan pengoptimalan, pengkompilasi memanfaatkan profil yang dibangunnya pada waktu proses untuk membuat keputusan khusus untuk menjalankan program Anda saat ini. Di .NET 9, pengkompilasi JIT 64-bit menggunakan data PGO untuk meningkatkan performa pemeriksaan jenis.

Menentukan jenis objek memerlukan panggilan ke dalam runtime, yang dilengkapi dengan penalti performa. Ketika jenis objek perlu diperiksa, pengkompilasi JIT 64-bit memancarkan panggilan ini demi kebenaran (pengkompilasi biasanya tidak dapat mengesampingkan kemungkinan apa pun, bahkan jika mereka tampak tidak mungkin). Namun, jika data PGO menunjukkan objek kemungkinan jenis tertentu, kompilator JIT 64-bit sekarang memancarkan jalur cepat yang murah memeriksa jenis tersebut, dan kembali ke jalur lambat panggilan ke runtime hanya jika perlu.

Vektorisasi Arm64 di pustaka .NET

Implementasi baru EncodeToUtf8 memanfaatkan kemampuan kompilator JIT 64-bit untuk memancarkan instruksi beban/penyimpanan multi-register di Arm64. Perilaku ini memungkinkan program untuk memproses potongan data yang lebih besar dengan instruksi yang lebih sedikit. Aplikasi .NET di berbagai domain akan melihat peningkatan throughput pada perangkat keras Arm64 yang mendukung fitur-fitur ini. Beberapa tolok ukur memotong waktu eksekusi mereka lebih dari setengahnya.

.NET SDK

Pengujian Unit

Bagian ini menjelaskan pembaruan untuk pengujian unit di .NET 9: menjalankan pengujian secara paralel, dan output pengujian pencatat terminal.

Menjalankan pengujian secara paralel

Di .NET 9, dotnet test lebih terintegrasi sepenuhnya dengan MSBuild. Karena MSBuild mendukung pembangunan secara paralel, Anda dapat menjalankan pengujian untuk proyek yang sama di berbagai kerangka kerja target secara paralel. Secara default, MSBuild membatasi jumlah proses paralel ke jumlah prosesor di komputer. Anda juga dapat mengatur batas Anda sendiri menggunakan sakelar -maxcpucount . Jika Anda ingin menolak paralelisme, atur TestTfmsInParallel properti MSBuild ke false.

Tampilan pengujian pencatat terminal

Pelaporan hasil pengujian untuk dotnet test sekarang didukung langsung di pencatat terminal MSBuild. Anda mendapatkan pelaporan pengujian dengan fitur yang lebih lengkap saat pengujian berjalan (menampilkan nama pengujian yang sedang berjalan) dan setelah pengujian selesai (kesalahan pengujian apa pun dirender dengan cara yang lebih baik).

Untuk informasi selengkapnya tentang pencatat terminal, lihat opsi build dotnet.

Alat .NET roll-forward

Alat .NET adalah aplikasi yang bergantung pada kerangka kerja yang dapat Anda instal secara global atau lokal, lalu jalankan menggunakan .NET SDK dan runtime .NET yang diinstal. Alat-alat ini, seperti semua aplikasi .NET, menargetkan versi utama tertentu dari .NET. Secara default, aplikasi tidak berjalan pada versi .NET yang lebih baru. Penulis alat telah dapat memilih untuk menjalankan alat mereka pada versi runtime .NET yang lebih baru dengan mengatur RollForward properti MSBuild. Namun, tidak semua alat melakukannya.

Opsi baru untuk dotnet tool install memungkinkan pengguna memutuskan bagaimana alat .NET harus dijalankan. Ketika Anda menginstal alat melalui dotnet tool install, atau ketika Anda menjalankan alat melalui dotnet tool run <toolname>, Anda dapat menentukan bendera baru yang disebut --allow-roll-forward. Opsi ini mengonfigurasi alat dengan mode Majorroll-forward . Mode ini memungkinkan alat untuk berjalan pada versi utama .NET yang lebih baru jika versi .NET yang cocok tidak tersedia. Fitur ini membantu pengadopsi awal menggunakan alat .NET tanpa penulis alat harus mengubah kode apa pun.

Lihat juga