Neuigkeiten in .NET Bibliotheken für .NET 11

In diesem Artikel werden neue Features in den .NET-Bibliotheken für .NET 11 beschrieben. Es wurde zuletzt für Preview 7 aktualisiert.

Diagnose und Prozessausführung

Prozess-API-Erweiterung

Process verfügt über eine Vielzahl neuer APIs, die häufige Anwendungsfälle abdecken, für die Sie zuvor OutputDataReceived/ErrorDataReceived-Ereignisse manuell verdrahten oder P/Invoke verwenden mussten.

Hilfsprogramme zum Ausführen und Erfassen

Mit neuen One-Shot-APIs können Sie einen Prozess starten und das Ergebnis ohne manuelle Einrichtung erhalten:

// One-shot capture: stdout and stderr together, plus exit code.
ProcessTextOutput result = await Process.RunAndCaptureTextAsync(
    "git", ["status", "--porcelain"]);

Console.WriteLine(result.StandardOutput);
Console.WriteLine($"Exit code: {result.ExitStatus.ExitCode}");

Der vollständige Satz von Helfern umfasst:

Starten ohne Rückmeldung

  • Process.StartAndForget – startet einen untergeordneten Prozess, wenn Sie nicht darauf warten möchten; die Laufzeit trennt das Handle automatisch.
  • ProcessStartInfo.StartDetached – wird von der Sitzung/Konsole des übergeordneten Prozesses getrennt, sodass der untergeordnete Prozess auch nach dem Beenden des Terminals weiterlaufen kann.
  • ProcessStartInfo.KillOnParentExit (nur unter Windows) – der untergeordnete Prozess wird beendet, wenn der übergeordnete Prozess beendet wird.

SafeProcessHandle-Lebenszyklusmethoden

SafeProcessHandle erhält Lebenszyklusmethoden für fortgeschrittene Szenarien:

Präzisere Steuerung des Hebels

Angehaltene Starts und Prozesssuche

System.Diagnostics.Process bietet eine bessere Kontrolle über das Starten und Suchen von Prozessen:

  • ProcessStartInfo.StartSuspended startet einen Prozess in einem angehaltenen Zustand unter Windows und macOS. Kombinieren Sie es mit SafeProcessHandle.Resume(), damit es ausgeführt wird, sobald Sie alle Einrichtungsschritte abgeschlossen haben, z. B. das Anhängen eines Debuggers oder das Konfigurieren von Auftragsobjekten.
  • Process.TryGetProcessById(Int32, Process) gibt false zurück, anstatt eine Ausnahme auszulösen, wenn kein Prozess mit der angegebenen ID existiert.
  • <xref:Microsoft.Win32.SafeHandles.SafeProcessHandle.Open(System.Int32)> und <xref:Microsoft.Win32.SafeHandles.SafeProcessHandle.TryOpen(System.Int32,Microsoft.Win32.SafeHandles.SafeProcessHandle@)> öffnen ein Handle für einen vorhandenen Prozess anhand seiner ID.
var startInfo = new ProcessStartInfo("worker.exe") { StartSuspended = true };
using var process = Process.Start(startInfo)!;

// Attach diagnostics or configure job objects while the process is suspended,
// then call Resume to start execution once your setup is complete.
AttachProfiler(process);
process.SafeHandle.Resume();

Konsolen-FORCE_COLOR-Unterstützung

.NET Konsolenausgabe berücksichtigt nun den Standard FORCE_COLOR neben der vorhandenen NO_COLOR-Unterstützung. Wenn FORCE_COLOR gesetzt ist, unterdrückt Console.IsOutputRedirected ANSI-Escape-Codes nicht mehr. Dies ist nützlich, wenn Sie die Ausgabe von dotnet run durch tee weiterleiten, an einen CI-Protokoll-Viewer oder durch less -R:

FORCE_COLOR=1 dotnet run | tee build.log

Arbeitsspeicher-Streamadapter

Vier neue Stream-Typen kapseln gängige In-Memory-Daten, sodass Sie sie an jede API übergeben können, die ein Stream erwartet, ohne sie zuvor in ein MemoryStream zu kopieren:

  • ReadOnlyMemoryStream macht einen ReadOnlyMemory<byte> als schreibgeschützten Datenstrom verfügbar.
  • WritableMemoryStream macht einen schreibbaren Memory<byte> Datenstrom mit fester Größe verfügbar.
  • ReadOnlySequenceStream stellt einen ReadOnlySequence<byte> (z. B. Puffer von System.IO.Pipelines) als Datenstrom bereit, ohne ihn zu einer flachen Struktur zusammenzuführen.
  • StringStream liest einen string oder ReadOnlyMemory<char> als Datenstrom mit einer angegebenen Codierung.
using System.IO;
using System.Text;

// Pass a string to an API that takes a Stream, with no intermediate byte[] needed.
using Stream config = new StringStream(yamlText, Encoding.UTF8);
var settings = ParseConfiguration(config);

// Expose an existing buffer as a read-only stream, for example as an HTTP request body.
ReadOnlyMemory<byte> payload = GetPayload();
using Stream body = new ReadOnlyMemoryStream(payload);
await httpClient.PostAsync(uri, new StreamContent(body));

ReadOnlySequenceStream ist besonders nützlich mit System.IO.Pipelines, da es direkt über die Segmente einer ReadOnlySequence<byte> arbeitet, anstatt eine zusammenhängende Kopie zuzuordnen.

Text, Serialisierung und Datenverarbeitung

Verbesserungen bei Zeichenfolgen und Zeichen

.NET 11 führt erhebliche Verbesserungen an Zeichenfolgen- und Zeichenbearbeitungs-APIs ein, wodurch die Arbeit mit Unicode-Zeichen und Runen erleichtert wird.

Rune-Unterstützung in String-Methoden

Die String Klasse enthält jetzt Methoden, die Parameter akzeptieren Rune , sodass Sie Zeichenfolgen mithilfe von Unicode-Skalarwerten direkt durchsuchen, ersetzen und bearbeiten können. Zu diesen neuen Methoden gehören:

Viele dieser Methoden enthalten Überladungen, die einen Parameter vom Typ StringComparison für kulturbewusste Vergleiche entgegennehmen.

Char.Equals mit StringComparison

Die Char Struktur enthält jetzt eine Char.Equals(Char, StringComparison) Methode, die einen StringComparison Parameter akzeptiert, wodurch Sie Zeichen kulturabhängig oder ordinal vergleichen können.

Runenunterstützung in TextInfo

Die TextInfo-Klasse bietet jetzt TextInfo.ToLower(Rune)- und TextInfo.ToUpper(Rune)-Methoden, die Rune-Parameter annehmen, mit denen Sie Fallkonvertierungen für einzelne Unicode-Skalarwerte ausführen können.

StringBuilder.MoveChunks

Um Inhalte ohne Kopieren von Zeichen zu übertragen, verwenden Sie die neue statische StringBuilder.MoveChunks(StringBuilder) Methode, mit der alle Inhalte aus einer Quelle StringBuilder in eine neue StringBuilderverschoben werden. Nach dem Aufruf hat die Quelle StringBuilder eine Länge von 0:

var source = new StringBuilder("Hello, ");
source.Append("World!");

// MoveChunks transfers all content from source to a new StringBuilder.
// After the call, source contains no characters.
StringBuilder dest = StringBuilder.MoveChunks(source);
Console.WriteLine(dest);          // Hello, World!
Console.WriteLine(source.Length); // 0

Verbesserungen bei der Base64-Codierung

.NET 11 fügt dem vorhandenen Base64-Typ neue APIs und Überladungen hinzu und bietet umfassende Unterstützung für base64-Codierung und -Decodierung. Diese Ergänzungen bieten im Vergleich zu bestehenden Methoden eine verbesserte Leistung und Flexibilität.

Neue Base64-APIs

Die neuen APIs unterstützen Codierungs- und Decodierungsvorgänge mit verschiedenen Eingabe- und Ausgabeformaten:

Diese Methoden bieten sowohl hochgradige Komfortmethoden (die Arrays oder Zeichenfolgen zuordnen und zurückgeben) als auch niedrigstufige span-basierte Methoden (für Nullzuordnungsszenarien).

System.Text.Unicode verfügt über zwei neue ergänzende Features. Utf16.IsValid(ReadOnlySpan<Char>) gibt an, ob eine UTF-16-Sequenz wohlgeformt ist, ohne sie zweimal zu scannen, und Utf8.IndexOfInvalidSubsequence(ReadOnlySpan<Byte>) / Utf16.IndexOfInvalidSubsequence(ReadOnlySpan<Char>) geben die Position der ersten fehlerhaften Codeeinheitensequenz zurück (oder -1 bei gültiger Eingabe). Mit diesen Methoden können Parser, Validatoren und Serialisierer präzise Fehler anstelle von generischen Codierungsfehlermeldungen melden.

ReadOnlySpan<byte> bytes = [0xC3, 0x28]; // invalid UTF-8
int badIndex = Utf8.IndexOfInvalidSubsequence(bytes); // 0

ReadOnlySpan<char> chars = "valid \uD83D\uDC4D end"; // valid UTF-16 (👍 emoji)
bool ok = Utf16.IsValid(chars); // true

Verbesserungen bei System.Text.Json

Abrufen von generischen Typinformationen

Ein häufiges Muster beim Arbeiten mit System.Text.Json Typmetadaten ist das Abrufen eines JsonTypeInfo<T> von JsonSerializerOptions. Bisher musste man die nicht-generische Methode GetTypeInfo(Type) manuell herunterstufen. Die neuen generischen Methoden JsonSerializerOptions.GetTypeInfo<T>() und JsonSerializerOptions.TryGetTypeInfo<T>(JsonTypeInfo<T>) geben direkt stark typisierte Metadaten zurück, wodurch die Herunterstufung entfällt.

JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
options.MakeReadOnly();

// Before: manual downcast required
JsonTypeInfo<MyRecord> info1 = (JsonTypeInfo<MyRecord>)options.GetTypeInfo(typeof(MyRecord));

// After: generic method returns the right type directly
JsonTypeInfo<MyRecord> info2 = options.GetTypeInfo<MyRecord>();

// TryGetTypeInfo variant for cases where the type may not be registered
if (options.TryGetTypeInfo<MyRecord>(out JsonTypeInfo<MyRecord>? typeInfo))
{
    // Use typeInfo
    _ = typeInfo;
}

Dies ist besonders hilfreich beim Arbeiten mit Quellgenerierungs-, NativeAOT- und polymorphen Serialisierungsszenarien, in denen der Typmetadatenzugriff üblich ist.

Standardwerte benennen und ignorieren

Die jetzt verfügbaren System.Text.Json Optionen zum Benennen und Ignorieren umfassen:

  • JsonNamingPolicy.PascalCase: Eine neue eingebaute Benennungsrichtlinie, die Eigenschaftsnamen in PascalCase konvertiert. Es ergänzt die vorhandenen camelCase-, snake_case- und kebab-case-Richtlinien.
  • Benennungsrichtlinie pro Mitglied: Mit dem neuen System.Text.Json.Serialization.JsonNamingPolicyAttribute Attribut können Sie die Benennungsrichtlinie für einzelne Eigenschaften oder Felder außer Kraft setzen, sodass Sie ein differenziertes Steuerelement ohne einen benutzerdefinierten Konverter erhalten.
  • Ignorierbedingungen auf Typebene: Durch die Verwendung von System.Text.Json.Serialization.JsonIgnoreAttribute auf Klassen- oder Strukturebene wird das Standard-Ignorierverhalten für alle Mitglieder festgelegt, sodass Sie das Attribut nicht mehr bei jeder nullfähigen Eigenschaft wiederholen müssen.
// Type-level JsonIgnore: all members use WhenWritingNull by default
// Per-member JsonNamingPolicy: EventName uses camelCase even though the
// serializer options use PascalCase
var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.PascalCase
};

var data = new EventData { EventName = "Launch", Notes = null };
string json = JsonSerializer.Serialize(data, options);
Console.WriteLine(json);
// {"eventName":"Launch"}  -- Notes omitted (null), EventName camel-cased

Unterstützung für diskriminierte Vereinigungen in F#

Der Serializer unterstützt nun standardmäßig diskriminierte Vereinigungen in F#. Anwendungen, die Typen zwischen F#-Produzenten und C#-Konsumenten gemeinsam verwenden, benötigen für die häufigsten Formen keinen benutzerdefinierten Konverter mehr:

type Shape =
    | Circle of radius: float
    | Square of side: float

let json = System.Text.Json.JsonSerializer.Serialize(Circle 1.5)
// {"$type":"Circle","radius":1.5}

Utf8JsonWriter.Reset mit Optionen

Reset akzeptiert nun einen JsonWriterOptions Parameter, sodass Writer-Instanzen mit verschiedenen Optionen neu gruppiert werden können, ohne einen neuen Writer zuzuweisen:

using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true });
writer.WriteStartObject();
writer.WriteString("name", "example");
writer.WriteEndObject();
writer.Flush();

// Reset with different options for next use — no new allocation needed
stream.SetLength(0);
writer.Reset(stream, new JsonWriterOptions { Indented = false });

Verbesserungen für SerializeAsyncEnumerable

JsonSerializer.SerializeAsyncEnumerable bietet zwei neue Funktionen:

  • PipeWriter Ziel: Bei pipelinebasierten E/A-Szenarien akzeptieren neue Überladungen ein PipeWriter Als Ausgabeziel, sodass das JSON-Streaming einfach direkt integriert werden kann.
  • topLevelValues Parameter: Legen Sie für die NDJSON-Ausgabe diesen Parameter so fest, dass true jedes Element als JSON-Wert auf oberster Ebene geschrieben wird, der durch Newlines getrennt ist, anstatt alle Elemente in einem JSON-Array umzuschließen. Sowohl die Stream- als auch die PipeWriter-Überladungen unterstützen den Parameter.
static async IAsyncEnumerable<int> GenerateNumbers()
{
    for (int i = 0; i < 5; i++)
    {
        yield return i;
        await Task.Yield();
    }
}

var pipe = new Pipe();

// Write a JSON array: [0,1,2,3,4]
await JsonSerializer.SerializeAsyncEnumerable(
    pipe.Writer,
    GenerateNumbers());

// Write NDJSON (one value per line): 0\n1\n2\n3\n4\n
await JsonSerializer.SerializeAsyncEnumerable(
    pipe.Writer,
    GenerateNumbers(),
    topLevelValues: true);

Serialisierung des C#-Union-Typs

System.Text.Json kann jetzt C#-Union-Typen serialisieren und deserialisieren. Der Serialisierer erkennt eine Union über den neuen JsonTypeInfoKind.Union-Vertragstyp, liest und schreibt den aktiven Fall und unterstützt sowohl den reflexionsbasierten Serialisierer als auch den Quellgenerator. Wenn Sie eine Union serialisieren, schreibt System.Text.Json den Wert der jeweils aktiven Variante, sodass sich eine Union aus int und string verlustfrei serialisieren und deserialisieren lässt:

{
  "id": 1,
  "payload": "hello"
}
{
  "id": 2,
  "payload": 42
}

Mit den neuen JsonUnionAttribute und JsonUnionCaseInfo APIs können Sie zusammen mit den Typklassifizierer-APIs (JsonTypeClassifier und JsonSerializerOptions.TypeClassifiers) anpassen, wie Fälle ermittelt und benannt werden. Union-Typen sind eine Vorschaufunktion der C#-Sprache. Weitere Informationen finden Sie unter Neuigkeiten in C# 15.

Polymorphismus-Inferenz in geschlossenen Hierarchien

JsonSerializerOptions fügt JsonSerializerOptions.InferClosedTypePolymorphism hinzu, damit der Serialisierer polymorphe Metadaten für geschlossene C#-Hierarchien ableiten kann, ohne dass explizite JsonDerivedTypeAttribute Anmerkungen für jeden Basistyp erforderlich sind. Explizite Registrierungen haben weiterhin Vorrang.

Verbesserungen von regulären Ausdrücken

AnyNewLine-Option

Ein neues RegexOptions.AnyNewLine-Flag bewirkt, dass ^, $ und . den vollständigen Satz von Unicode-Zeilenumbruchzeichen als Zeilenendzeichen behandeln – nicht nur \n. Dies hilft beim Analysieren von Text, der Windows (\r\n), Unix (\n) und Unicode-spezifische Zeilenenden (\u0085, \u2028, \u2029) kombiniert.

string text = "line1\r\nline2\u0085line3\u2028line4";

// RegexOptions.AnyNewLine makes ^, $, and . treat all Unicode newline
// sequences as line terminators, not just \n.
MatchCollection matches = Regex.Matches(
    text,
    @"^line\d$",
    RegexOptions.Multiline | RegexOptions.AnyNewLine);

Console.WriteLine(matches.Count); // 4

Fehlerbehebungen an der Regex-Engine und am Quellgenerator

.NET 11 enthält mehrere Regex-Korrekturen und Codequalitätskorrekturen:

  • Das Nicht-Rückverfolgungsmodul benötigt keine superlineare Zeit mehr für bestimmte geschachtelte Schleifenmuster und erzeugt korrekte Ergebnisse für Fälle, die zuvor abgespalten waren.
  • Der regex-Compiler und der Quellgenerator behandeln resumeAt ordnungsgemäß, wenn eine bedingte Eigenschaft innerhalb eines Schleifentexts angezeigt wird.
  • Der SYSLIB1045 Codekorrekturer erstellt keine doppelten Klassennamen mehr, wenn sie auf mehrere partielle Deklarationen derselben Klasse angewendet werden.

Komprimierungs- und Archivformate

Komprimierungsverbesserungen

.NET 11 enthält mehrere Verbesserungen an Komprimierungs-APIs.

Zugriffsmodi für ZIP-Archiveinträge

Die ZipArchiveEntry Klasse unterstützt jetzt das Öffnen von Einträgen mit bestimmten Dateizugriffsmodi über neue Überladungen: ZipArchiveEntry.Open(FileAccess) und ZipArchiveEntry.OpenAsync(FileAccess, CancellationToken). Diese Überladungen akzeptieren einen FileAccess-Parameter und ermöglichen es Ihnen, ZIP-Einträge für den Lese-, Schreib- oder Lese-/Schreibzugriff zu öffnen.

Darüber hinaus gibt es eine neue CompressionMethod-Eigenschaft, die die für einen Eintrag verwendete Komprimierungsmethode über die ZipCompressionMethod-Enumeration bekannt gibt, die Werte für Stored, Deflate und Deflate64 enthält.

ZIP CRC32-Überprüfung

ZipArchive überprüft die CRC32-Prüfsumme beim Lesen von ZIP-Einträgen. Beschädigte oder abgeschnittene Archive, die zuvor ohne Fehler durchliefen, lösen jetzt einen Fehler aus InvalidDataException, wodurch Probleme mit der Datenintegrität frühzeitig erkannt werden können.

Unterstützung für ZIP-Archivkennworte

ZipArchiveEntry unterstützt jetzt kennwortgeschützte Einträge für Lese- und Schreibvorgänge. Verwenden Sie die neuen kennwortgestützten ZipArchiveEntry.Open(ReadOnlySpan<Char>)- und ZipArchiveEntry.OpenAsync(ReadOnlySpan<Char>, CancellationToken)-Überladungen, und verwenden Sie beim Erstellen verschlüsselter Einträge das Kennwort zusammen mit ZipEncryptionMethod.

Änderung des DeflateStream- und GZipStream-Verhaltens

Ab .NET 11 schreiben DeflateStream und GZipStream immer Formatkopf- und Fußzeilen in den Ausgabedatenstrom, auch wenn keine Daten geschrieben werden. Dadurch wird sichergestellt, dass die Ausgabe ein gültiger komprimierter Datenstrom gemäß den Spezifikationen "Deflate" und "GZip" ist.

Bisher haben diese Datenströme keine Ausgabe erzeugt, wenn keine Daten geschrieben wurden, was zu einem leeren Ausgabedatenstrom führt. Diese Änderung stellt die Kompatibilität mit Tools sicher, die ordnungsgemäß formatierte komprimierte Datenströme erwarten.

Weitere Informationen finden Sie unter DeflateStream und GZipStream schreiben Kopf- und Fußzeilen für leere Nutzdaten.

Span-basierte Deflate-, ZLib- und GZip-APIs

System.IO.Compression bietet nun Span<byte>/ReadOnlySpan<byte> Einstiegspunkte zum Kodieren und Dekodieren für die Formate Deflate, ZLib und GZip. Die neuen APIs für Typen wie DeflateEncoder, ZLibEncoder und GZipEncoder entsprechen in ihrer Struktur BrotliEncoder/BrotliDecoder und den Zstandard-Primitiven. Sie können Puffer komprimieren und dekomprimieren, ohne ein Stream zuzuweisen. Dies ist nützlich für Szenarien mit hohem Durchsatz, z. B. Protokollparser, Protokollversandgeräte und Middleware, die bereits auf Spans ausgeführt werden.

ReadOnlySpan<byte> source = [0x48, 0x65, 0x6C, 0x6C, 0x6F]; // "Hello"
byte[] buffer = new byte[source.Length + 32];
Span<byte> destination = buffer;

using ZLibEncoder encoder = new();
OperationStatus status = encoder.Compress(
    source, destination, out int bytesConsumed, out int bytesWritten,
    isFinalBlock: true);

Console.WriteLine($"Compressed {bytesConsumed} bytes into {bytesWritten} bytes. Status: {status}");

Zstandard-Komprimierung

Die Zstandard-Komprimierungs-APIs, zum Beispiel ZstandardStream und ZstandardEncoder, sind jetzt Teil des System.IO.Compression-Namespaces, neben DeflateStream, GZipStream und BrotliStream. Die API-Oberfläche ist andernfalls unverändert.

Tar-Archivformatauswahl

Neue Überladungen von CreateFromDirectory und CreateFromDirectoryAsync akzeptieren einen TarEntryFormat-Parameter, sodass Sie das Archivformat direkt steuern können. CreateFromDirectory stellte früher immer Pax-Archive her. Die neuen Überladungen unterstützen alle vier Tar-Formate – Pax, Ustar, GNU und V7 – zur Kompatibilität mit bestimmten Tools und Umgebungen.

// Create a GNU format tar archive for Linux compatibility
TarFile.CreateFromDirectory("/source/dir", "/dest/archive.tar",
    includeBaseDirectory: true, format: TarEntryFormat.Gnu);

// Create a Ustar format archive for broader compatibility
using Stream outputStream = File.OpenWrite("/dest/ustar.tar");
TarFile.CreateFromDirectory("/source/dir", outputStream,
    includeBaseDirectory: false, format: TarEntryFormat.Ustar);

// Async version
CancellationToken cancellationToken = CancellationToken.None;
await TarFile.CreateFromDirectoryAsync("/source/dir", "/dest/archive.tar",
    includeBaseDirectory: true, format: TarEntryFormat.Pax,
    cancellationToken: cancellationToken);

TarReader kann nun auch Einträge lesen, die die GNU Sparse Format 1.0 (PAX)-Darstellung verwenden. Die frühere Darstellung von 0.1 wurde bereits unterstützt. Wenn 1.0-Unterstützung vorhanden ist, TarReader entspricht es, was moderne tar Implementierungen standardmäßig für sparse Dateien schreiben.

Sammlungen, numerische Typen und E/A auf niedriger Ebene

Verbesserungen bei LINQ-Joins

LINQ fügt Verknüpfungsverbesserungen hinzu, einschließlich einer neuen FullJoin Operation und Tupel-Rückgabeüberladungen für die vorhandenen Join- und GroupJoin-Methoden. Diese APIs sind auf Enumerable, Queryable und AsyncEnumerable verfügbar.

LeftJoin, RightJoin und FullJoin

Da die drei äußeren Join-Operationen direkt Tupel zurückgeben, können Sie diese mithilfe von Musterabgleich und Dekonstruktion problemlos verarbeiten:

  • Enumerable.LeftJoin - Gibt alle Elemente aus der linken (äußeren) Sequenz zurück. Wenn kein übereinstimmende Element in der rechten (inneren) Sequenz vorhanden ist, ist default das innere Element (in der Regel null für Referenztypen).
  • Enumerable.RightJoin - Gibt alle Elemente aus der rechten (inneren) Sequenz zurück. Wenn keine übereinstimmenden Elemente in der linken (äußeren) Sequenz vorhanden sind, ist default das äußere Element (in der Regel null für Referenztypen).
  • Enumerable.FullJoin — Gibt alle Elemente aus beiden Sequenzen zurück, wobei default auf der jeweiligen Seite verwendet wird, wenn keine Übereinstimmung vorliegt.
var products = new List<(int Id, string Name, string? Category)>
{
    (1, "Laptop", "Electronics"),
    (2, "Mouse", "Electronics"),
    (3, "Orphan", null), // No matching category
};
var categories = new List<(string Name, string Description)>
{
    ("Electronics", "Electronic devices"),
    ("Furniture", "Office furniture"), // No matching product
};

// LeftJoin: all products, matched categories (null if none)
var leftJoined = products.LeftJoin(
    categories,
    p => p.Category,
    c => c.Name);

foreach (var (product, category) in leftJoined)
    Console.WriteLine($"{product.Name}: {category.Description ?? "(none)"}");
// Laptop: Electronic devices
// Mouse: Electronic devices
// Orphan: (none)

// FullJoin: all products and categories, paired where they match
var fullJoined = products.FullJoin(
    categories,
    p => p.Category,
    c => c.Name);

foreach (var (product, category) in fullJoined)
    Console.WriteLine(
        $"{product.Name ?? "(none)"}: {category.Description ?? "(none)"}");
// Laptop: Electronic devices
// Mouse: Electronic devices
// Orphan: (none)
// (none): Office furniture

IEEE 754-Dezimal-Gleitkommatypen

System.Numerics fügt Decimal32, Decimal64 und Decimal128 hinzu, welche die Semantik für dezimale Gleitkommazahlen nach IEEE 754-2019 implementieren. Diese Typen unterstützen generische Mathematik, Unendlichkeitswerte und NaN-Werte und können hilfreich sein, wenn Sie IEEE-Dezimalverhalten anstelle von Decimal benötigen.

Partielle numerische Analyse

INumberBase<TSelf>.TryParsePartial fügt Überladungen für partielles Parsing hinzu, die die verarbeitete Eingabe zurückmelden. Verwenden Sie diese API, um durch Trennzeichen getrennte Formate wie CSV zu analysieren, sodass Sie keine Teilzeichenfolgen kopieren.

Generischer Complex<T>

Complex<T> ist jetzt verfügbar, sodass komplexe Arithmetik mehrere Gleitkommatypen verwenden kann, einschließlich float, Half, und BFloat16die neuen Dezimalkommatypen.

Überladungen von Join und GroupJoin, die Tupel zurückgeben

Neue Überladungen von Enumerable.Join und Enumerable.GroupJoin geben Tupel direkt zurück, ohne dass ein Ergebnisselektor erforderlich ist, und akzeptieren einen optionalen IEqualityComparer<T>-Parameter. Die Überladung mit optionalem Vergleich ist auch für die Operationen FullJoin, LeftJoin und RightJoin verfügbar.

var products = new[] { (Id: 1, Name: "Laptop"), (Id: 2, Name: "Mouse") };
var orders = new[] { (ProductId: 1, Qty: 3), (ProductId: 1, Qty: 1) };

var result = products.Join(orders, p => p.Id, o => o.ProductId);
foreach (var (product, order) in result)
    Console.WriteLine($"{product.Name}: qty={order.Qty}");
// Laptop: qty=3
// Laptop: qty=1

BFloat16-Unterstützung in BitConverter

Die BitConverter Klasse enthält jetzt Methoden zum Konvertieren zwischen BFloat16 Werten und Bytearrays oder Bitdarstellungen. Zu diesen neuen Methoden gehören:

BFloat16 (Brain Floating Point) ist ein 16-Bit-Gleitkommaformat, das häufig in maschinellem Lernen und wissenschaftlichem Computing verwendet wird.

Gleitkomma-Hexformatierung und Analyse

double, floatund Half kann jetzt in ihrer hexadezimalen IEEE-754-Form formatiert und analysiert werden. Die Hexadezimalform bewahrt jedes Bit des zugrunde liegenden Werts, was sie zur richtigen Wahl für Golden-File-Tests, die sprachübergreifende Interoperabilität mit C/C++ printf("%a", ...) und alle Szenarien macht, in denen die Umwandlung eines double in Dezimaltext und zurück zu verlustreich ist.

double value = Math.PI;

// Format as hexadecimal IEEE-754: preserves all bits exactly
string hex = value.ToString("X"); // e.g., "0X1.921FB54442D18P+1"
double roundTripped = double.Parse(hex, NumberStyles.HexFloat);

Console.WriteLine(roundTripped == value); // True — exact round-trip

Verbesserungen bei numerischen Daten

Matrix4x4.GetDeterminant() verwendet nun eine SSE-vektorisierte Implementierung, die die Leistung um ca. 15%verbessert.

Zufällige generische Methoden

Random erhält zwei neue generische Methoden, die mit jedem numerischen Typ arbeiten, der die entsprechenden generischen mathematischen Schnittstellen implementiert:

  • Random.NextInteger — Generiert eine zufällige ganze Zahl vom Typ T , wobei T implementiert IBinaryInteger<T> und IMinMaxValue<T>. Überladungen akzeptieren eine obere Grenze oder sowohl untere als auch obere Begrenzungen.
  • Random.NextBinaryFloat — Generiert einen zufälligen Gleitkommawert vom Typ T, wobei TIBinaryFloatingPointIeee754<T> implementiert.
// Generate a random integer of any binary integer type
int i = Random.Shared.NextInteger<int>();
long l = Random.Shared.NextInteger<long>(0L, 100L);
byte b = Random.Shared.NextInteger<byte>(maxValue: (byte)10);

// Generate a random floating-point value of any IEEE-754 type
float f = Random.Shared.NextBinaryFloat<float>();
double d = Random.Shared.NextBinaryFloat<double>();
Half h = Random.Shared.NextBinaryFloat<Half>();

Console.WriteLine($"int={i}, long={l}, byte={b}");
Console.WriteLine($"float={f}, double={d}, Half={h}");

Cross-Lane-Vektorvorgänge

Vector64<T>, Vector128<T>, Vector256<T>, Vector512<T> und Vector<T> erhalten eine Reihe von Methoden zum Erstellen und Zusammensetzen von Lanes, die zuvor manuell geschriebene Shuffles erforderten. Die neuen Methoden lassen sich in einige Kategorien einteilen:

  • Musterkonstruktion:CreateGeometricSequence, CreateAlternatingSequenceund CreateHarmonicSequence erstellen Sie einen Vektor aus einem Anfangswert und einer Regel.
  • Verschachteln und entflechten:Zip, ZipLower/ZipUpper, Unzip, UnzipEven/UnzipOdd.
  • Neu anordnen: Die Concat Familie (ConcatLowerLower, ConcatLowerUpper, ConcatUpperLower, ConcatUpperUpper) und Reverse.
using System.Runtime.Intrinsics;

// {1, 2, 4, 8} — each lane is the previous lane times two
Vector128<int> powers = Vector128.CreateGeometricSequence(1, 2);

// Interleave two vectors lane-by-lane
(Vector128<int> lower, Vector128<int> upper) =
    Vector128.Zip(Vector128.Create(1), Vector128.Create(2));

Diese Bausteine sind nützlich für die Bildverarbeitung, die digitale Audiosignalverarbeitung (Digital Signal Processing, DSP) und andere SIMD-intensive Workloads, die eine differenzierte Kontrolle über das Vektorelementlayout benötigen, ohne auf plattformspezifische systeminterne Elemente zurückgreifen zu müssen.

Verbesserungen bei Low-Level-I/O

SafeFileHandle Pipe-Unterstützung

SafeFileHandle gewinnt zwei neue Mitglieder:

SafeFileHandle.CreateAnonymousPipe(
    out SafeFileHandle readEnd,
    out SafeFileHandle writeEnd,
    asyncRead: true,
    asyncWrite: false);

using (readEnd)
using (writeEnd)
{
    // SafeFileHandle.Type reports the kind of OS object the handle refers to
    Console.WriteLine(readEnd.Type);   // Pipe
    Console.WriteLine(writeEnd.Type);  // Pipe
}

RandomAccess Pipe-Unterstützung

RandomAccess.Read und RandomAccess.Write funktionieren nun nicht nur mit regulären Datei-Handles, sondern auch mit nicht suchbaren Handles, wie beispielsweise Pipes.

Unter Windows verwendet Process nun Overlapped I/O für umgeleitete stdout/stderr-Ausgaben, wodurch die Blockierung des Thread-Pools in prozessintensiven Anwendungen verringert wird.

Verbesserungen bei Sammlungen

BitArray.PopCount

Die BitArray Klasse, die jetzt eine BitArray.PopCount() Methode enthält, gibt die Anzahl der Bits zurück, die im Array auf true gesetzt sind. Dies bietet eine effiziente Möglichkeit zum Zählen der gesetzten Bits ohne die manuelle Durchquerung des Arrays.

IReadOnlySet-Unterstützung in JSON-Serialisierung

Die JsonMetadataServices Klasse enthält jetzt eine JsonMetadataServices.CreateIReadOnlySetInfo Methode, die JSON-Serialisierungsunterstützung für IReadOnlySet<T> Sammlungen aktiviert.

EqualityComparer<T>.Create

Verwenden Sie die neue EqualityComparer<T>.Create-Methode, um aus einer Schlüsselselektorfunktion einen Gleichheitskomparator zu erstellen. Sie können für den Schlüsseltyp selbst ein optionales IEqualityComparer<T> übergeben:


// Create an equality comparer based on a key selector
var byName = EqualityComparer<(string Name, int Age)>.Create(p => p.Name);

var people = new HashSet<(string Name, int Age)>(byName)
{
    ("Alice", 30),
    ("Bob", 25),
    ("Alice", 40), // Duplicate by name — not added
};
Console.WriteLine(people.Count); // 2

Erweiterungen und Entwicklerplattform

Grundgerüst für Unterscheidungs-Unions

Hinweis

Dies ist ein Vorschaufeature in .NET 11.

.NET 11 führt System.Runtime.CompilerServices.UnionAttribute und System.Runtime.CompilerServices.IUnion in System.Runtime.CompilerServices ein. Diese Typen sind das Laufzeitgegenstück des C#-Entwurfs für Unterscheidungs-Unions. Sie sind noch nicht direkt für Benutzer sichtbar – der C#-Compiler und die Quellgeneratoren sind die vorgesehenen Erzeuger –, werden aber mit dem Framework bereitgestellt, damit Bibliotheken schon jetzt gegen diese API-Oberfläche entwickelt werden können.

Informationen zum sprachseitigen Entwurf finden Sie im C#-Unionsvorschlag.

MetadataLoadContext-Ergänzungen

MetadataLoadContext.GetLoadContext(Assembly) gibt den Ladekontext zurück, der ein bestimmtes Assembly erzeugt hat, und entspricht damit der seit Langem auf AssemblyLoadContext vorhandenen API. Dadurch wird eine Lücke bei Tools geschlossen, die Assemblys in einem isolierten MetadataLoadContext reflektieren und von einer Assembly-Referenz zu dem Kontext zurückverfolgen müssen, zu dem sie gehört:

using System.Reflection;
using System.Reflection.Metadata;

string[] paths = [typeof(object).Assembly.Location];
using var mlc = new MetadataLoadContext(new PathAssemblyResolver(paths));
Assembly asm = mlc.LoadFromAssemblyPath(typeof(object).Assembly.Location);

MetadataLoadContext owner = MetadataLoadContext.GetLoadContext(asm)!;
Console.WriteLine(ReferenceEquals(owner, mlc)); // true

URI-Datenschema-Konstante

Es wurde eine neue Uri.UriSchemeData Konstante hinzugefügt, die das data: URI-Schema darstellt. Diese Konstante stellt eine standardisierte Methode zum Verweisen auf Daten-URIs bereit.

Spiegelungsverbesserungen

Type.GetNullableUnderlyingType

System.Type erhält eine neue virtuelle Methode, Type.GetNullableUnderlyingType()die den zugrunde liegenden Werttyp für einen Nullable<T> Typ oder null für einen nicht nullablen Typ zurückgibt. Implementierungen sind verfügbar für Type, TypeBuilder, EnumBuilder, GenericTypeParameterBuilder und TypeDelegator:

Type nullableIntType = typeof(int?);
Type? underlying = nullableIntType.GetNullableUnderlyingType();
Console.WriteLine(underlying); // System.Int32

Type nonNullable = typeof(int);
Console.WriteLine(nonNullable.GetNullableUnderlyingType() is null); // True

ConstructorInfo.GetGenericArguments

ConstructorInfo.GetGenericArguments() verfügt nun über eine Überschreibung, die eine einheitliche Möglichkeit bietet, generische Typargumente für Konstruktordefinitionen abzurufen, und damit dem Verhalten entspricht, das bereits für andere MethodBase-Unterklassen verfügbar ist.

Assembly.Location-Außerkraftsetzung für AssemblyLoadContext

AssemblyLoadContext.SetAssemblyLocationOverride(Func<Assembly,String,String>) ist ein nur einmal festlegbarer Callback, der den von Assembly.Location gemeldeten Standort überschreiben kann. Diese API hilft Hostanwendungen, die Assemblies in temporären Pfaden oder virtualisierten Speicherorten ablegen, dem Code für Diagnose und Ressourcenladen stabile, aussagekräftige Speicherorte zu melden.

Reduzierte Konflikte in System.IO.Pipelines

System.IO.Pipelines reduziert Lese- und Schreibsperrkonflikte bei hohen „Auffächern nach innen“-Workloads. Interne Änderungen umfassen einen niedrigeren Sperrbereich, die Planung lokaler Warteschlangenfortsetzungen sowie Poolaktualisierungen, die die Cachelokalität verbessern.

Verbesserungen des StringSyntax-Attributs

Die StringSyntaxAttribute Klasse enthält jetzt Konstanten für allgemeine Programmiersprachen:

Diese Konstanten können mit dem StringSyntax Attribut verwendet werden, um eine bessere Toolunterstützung für Zeichenfolgenliterale bereitzustellen, die Code in diesen Sprachen enthalten.

Zwischenspeichern, Konfiguration und Protokollierung

Konfigurationsbindung

Microsoft.Extensions.Configuration fügt Microsoft.Extensions.Configuration.ConfigurationIgnoreAttribute hinzu, sodass Modelle einzelne Eigenschaften deklarativ von der Bindung ausnehmen können, ohne sich auf BindNonPublicProperties-Schalter oder benutzerdefinierte Konverter zu verlassen:

public sealed class AppOptions
{
    public string Endpoint { get; set; } = "";

    [ConfigurationIgnore]
    public string ComputedKey => Endpoint + ":default";
}

ConfigurationBinder bindet nun auch ein leeres Array an einen Konstruktorparameter, anstatt es auszuwerfen.

PhysicalFilesWatcher löst keinen Fehler mehr aus, wenn das Stammverzeichnis noch nicht vorhanden ist, und InMemoryDirectoryInfo löst .. und andere relative Segmente konsistent mit dem physischen Anbieter auf.

MemoryCache OpenTelemetry-Metriken

MemoryCache gibt jetzt einen integrierten Satz von OpenTelemetry (OTel)-kompatiblen Metriken ohne zusätzliches Adapterpaket aus. Zum Aktivieren setzen Sie MemoryCacheOptions.TrackStatistics auf true:

var cache = new MemoryCache(new MemoryCacheOptions
{
    TrackStatistics = true
});

Der neue Microsoft.Extensions.Caching.Memory.MemoryCache Meter veröffentlicht vier feststellbare Instrumente:

  • dotnet.cache.requests (mit einem dotnet.cache.request.type Tag, der hit von miss unterscheidet)
  • dotnet.cache.evictions
  • dotnet.cache.entries
  • dotnet.cache.estimated_size

Übergeben Sie System.Diagnostics.Metrics.IMeterFactory an die neue MemoryCache.MemoryCache(IOptions<MemoryCacheOptions>, ILoggerFactory, IMeterFactory)-Konstruktorüberladung für instanzspezifische Metriken. Ohne einen solchen werden die Instrumente prozessweit auf einem gemeinsamen Zähler zusammengefasst.

Verbesserungen bei der Überprüfung des Options-Generators

OptionsBuilder<TOptions> erhält eine neue generische OptionsBuilder<TOptions>.Validate-Überladung, die einen Typparameter anstelle eines Factory-Delegaten verwendet. Der Typ muss IValidateOptions<TOptions> implementieren und im Dependency-Injection-Container registriert sein. Dadurch wird die Optionsvalidierung an das Standardmuster für DI angepasst:

services.AddSingleton<IValidateOptions<MyOptions>, MyOptionsValidator>();
services.AddOptions<MyOptions>()
    .Bind(configuration.GetSection("MyOptions"))
    .Validate<MyOptionsValidator>();

Asynchrone ChangeToken.OnChange

OnChange verfügt jetzt über Func<Task>-Überladungen, sodass Sie asynchrone Rückrufe ohne Verwendung von async void ausführen können. Die erneute Registrierung erfolgt jetzt, nachdem die zurückgegebene Aufgabe abgeschlossen wurde.

Optionenfähige HybridCache-Fabriken

GetOrCreateAsync verfügt jetzt über Überladungen, die einen veränderbaren Factorykontext bereitstellen. Sie können grundlegende Optionen wie die Gültigkeitsdauer und die Größe des lokalen Caches über den wertgenerierenden Rückruf festlegen.

Asynchrone Überprüfung mit DataAnnotations

System.ComponentModel.DataAnnotations unterstützt jetzt die asynchrone Überprüfung. Eine Gültigkeitsprüfungsregel, die E/A ausführen muss – eine Datenbanksuche oder ein Remote-API-Aufruf – kann jetzt ausgeführt werden, ohne einen Thread zu blockieren. Es gibt drei neue Möglichkeiten zum Ausdrücken einer asynchronen Regel:

  • Leiten Sie von AsyncValidationAttribute ab und überschreiben Sie dessen Methode IsValidAsync.
  • Implementieren Sie IAsyncValidatableObject am Modell.
  • Rufen Sie die neuen Validator.ValidateObjectAsync, , TryValidateObjectAsync, ValidatePropertyAsyncund ValidateValueAsync Methoden auf.
using System;
using System.ComponentModel.DataAnnotations;

public sealed class ValidVatNumberAttribute : AsyncValidationAttribute
{
    protected override ValidationResult? IsValid(object? value, ValidationContext context) =>
        throw new InvalidOperationException("Validate this attribute with IsValidAsync.");

    protected override async Task<ValidationResult?> IsValidAsync(
        object? value, ValidationContext context, CancellationToken cancellationToken)
    {
        var registry = context.GetRequiredService<IVatRegistry>();
        return await registry.IsRegisteredAsync((string?)value, cancellationToken)
            ? ValidationResult.Success
            : new ValidationResult("That VAT number isn't registered with the tax authority.");
    }
}

public class Invoice
{
    [Required]
    [StringLength(14, MinimumLength = 8)]
    [RegularExpression(@"^[A-Z]{2}[A-Z0-9]+$")]
    [ValidVatNumber] // asynchronous
    public string VatNumber { get; set; } = "";
}

var context = new ValidationContext(model, serviceProvider, items: null);
await Validator.ValidateObjectAsync(model, context, validateAllProperties: true);

Microsoft.Extensions.Options erhält übereinstimmende Unterstützung: Optionen können asynchron überprüft werden, einschließlich beim Start über die neue IAsyncStartupValidator. Dadurch kann eine App schnell fehlschlagen, wenn eine Option, die eine Netzwerküberprüfung erfordert, falsch konfiguriert ist.

Konfiguration der Aktivitätsverfolgung

Mit einer neuen API für die Ablaufverfolgungs-Konfiguration in Microsoft.Extensions.Diagnostics können Sie die Activity-Ablaufverfolgung mit Regeln aktivieren und deaktivieren, anstatt ActivityListener-Instanzen manuell einzurichten. Rufen Sie AddTracing auf und geben Sie an, welche Aktivitätsquellen, Vorgänge und Listener aktiviert oder deaktiviert werden sollen. Regeln können über die Konfiguration gesteuert werden, sodass die Ablaufverfolgung ohne erneute Bereitstellung angepasst werden kann.

builder.Services.AddTracing(tracing =>
{
    tracing.EnableTracing(sourceName: "MyCompany.Orders");
    tracing.DisableTracing(sourceName: "MyCompany.Orders", operationName: "HealthCheck");
});

Das gleiche Release fügt ActivitySourceFactory hinzu und gibt ActivitySource frei, die beide fabrikgesteuerte Erstellung und aktualisierbare Listener unterstützen.

Generische methoden für die quellgenerierte Protokollierung

Der Protokollierungsquellgenerator unterstützt jetzt generische Methoden, die mit LoggerMessageAttribute versehen sind, vor allem um Boxing zu vermeiden. Generische Typparameter können Standardbeschränkungen verwenden, wie z. B. class, struct, unmanaged, Schnittstellen, Basistypen und new(). Die allows ref struct negative Einschränkung wird nicht unterstützt und erzeugt SYSLIB1011.

[LoggerMessage(0, LogLevel.Trace, "Received {Code} ({Length} bytes)")]
public static partial void PacketReceived<TCode>(ILogger logger, TCode code, int length)
    where TCode : struct, Enum;

Verbesserte Zuverlässigkeit für die Erkennung von Konfigurationsdateiänderungen

Der PhysicalFilesWatcher Typ, den Konfigurationsanbieter zum Erkennen von Konfigurationsdateiänderungen verwenden, umfasst mehrere Zuverlässigkeitsverbesserungen.

Es behandelt nun relative Pfade, fehlende Verzeichnisse und Dateisysteme, die die Dateibeobachtung nicht zuverlässiger unterstützen. Außerdem vermeidet es, Unterverzeichnisse zu überwachen, wenn dies nicht nötig ist.

Kryptografie

X25519 Diffie-Hellman Schlüsselaustausch

Die neue System.Security.Cryptography.X25519DiffieHellman abstrakte Klasse bietet eine saubere API für die elliptische X25519-Kurve Diffie-Hellman Algorithmus, der häufig in TLS 1.3-, SSH- und Signalprotokollimplementierungen verwendet wird. Plattformspezifische Implementierungen werden über X25519DiffieHellmanCng (Windows) und X25519DiffieHellmanOpenSsl (Linux und macOS) bereitgestellt, aber die portable GenerateKey() Factorymethode wählt automatisch die richtige:

// Generate key pairs for Alice and Bob
using X25519DiffieHellman alice = X25519DiffieHellman.GenerateKey();
using X25519DiffieHellman bob = X25519DiffieHellman.GenerateKey();

// Each party derives the shared secret using the other's public key
byte[] aliceShared = alice.DeriveRawSecretAgreement(bob);
byte[] bobShared = bob.DeriveRawSecretAgreement(alice);

// Both parties arrive at the same secret
Console.WriteLine(aliceShared.SequenceEqual(bobShared)); // True

Die Klasse unterstützt den vollständigen Schlüssellebenszyklus: Schlüsselgenerierung, PKCS#8 und SubjectPublicKeyInfo-Import/Export, PEM-Serialisierung und unformatierter Zugriff auf private/öffentliche Schlüssel.

CryptographicOperations.FixedTimeEquals-Überladung

Verwenden Sie für Geheimvergleichsszenarien, in denen der erwartete Wert ein einzelnes bekanntes Byte ist, die neue CryptographicOperations.FixedTimeEquals Überladung, die einen ReadOnlySpan<T> mit einem einzelnen byte Wert in konstanter Zeit vergleicht:

bool equal = CryptographicOperations.FixedTimeEquals(receivedSpan, 0x42);

Netzwerk- und Transportsicherheit

TLS-Handshake-Härtung

Zwei System.Net.Security Elemente verbessern die Zuverlässigkeit von TLS (Transport Layer Security):

  • SslStream serverseitige Korrekturen an der Grenzprüfung beim Handshake in TlsFrameHelper beheben mehrere Randfälle, die sich bei nicht wohlgeformten ClientHello-Datensätzen als IOException äußern könnten.
  • Unter Linux werden Fehler bei der Zertifikatvalidierung jetzt dem Peer als standardmäßige TLS-Alerts übermittelt, entsprechend dem Verhalten unter Windows. Beim Verbinden von Clients wird anstelle eines Verbindungsabbruchs ein handlungsfähiger Handshakefehler angezeigt.

HTTP-Anforderungskomprimierung

System.Net.Http fügt GZipCompressedContent-, BrotliCompressedContent- und ZstandardCompressedContent-Wrapper für Anforderungstextkörper hinzu. Diese Wrapper setzen den Content-Encoding-Header und streamen komprimierten Inhalt, während die Anfrage serialisiert wird.

Konfigurierbare HTTP-Verbindungsräumung

SocketsHttpHandler bietet jetzt SocketsHttpHandler.ShouldEvictConnection für Entscheidungen hinsichtlich Entfernungen pro Verbindung. Mit diesem Rückruf können Sie Verbindungen anhand von Alter, Endpunktdetails und DNS-Änderungen ausmustern, anstatt Richtlinien zu verwenden, die nur auf einer festen Lebensdauer basieren.

DNS-Eintragsauflösungs-APIs

System.Net.Dns fügt typisierte APIs zur Datensatzauflösung hinzu, darunter Dns.ResolveSrv(String), Dns.ResolveMx(String), Dns.ResolveCName(String), Dns.ResolveTxt(String), Dns.ResolvePtr(String) und Dns.ResolveNs(String), sowie Async-Varianten. Die Ergebnisse umfassen Datensätze, Antwortcode und Metadaten zur Gültigkeitsdauer (TTL) des negativen Caches über DnsResult<T>.

Automatisches HTTP/2-Downgrade für Windows-Authentifizierung

HttpClient wird automatisch auf HTTP/1.1 herabgestuft, wenn eine Anforderung Windows-Authentifizierung (NTLM/Negotiate) über HTTP/2 erfordert. Die HTTP/2-Spezifikation verbietet die verbindungsgebundenen Authentifizierungsschemas, auf die NTLM und Kerberos angewiesen sind, sodass diese Anforderungen zuvor fehlgeschlagen sind. Wenn das Downgrade aktiviert ist, funktionieren Anwendungen, die für Umgebungen mit gemischter Authentifizierung verwendet werden , die in Unternehmensintranets üblich sind, ohne explizite HttpRequestMessage.Version Außerkraftsetzungen.

QUIC-Streampriorität

QuicStream erhält eine QuicStream.Priority Eigenschaft und eine QuicStream.DefaultPriority Konstante, die HTTP/3-Streampriorisierung (RFC 9218) verfügbar macht. Prioritätswerte reichen von 0 (höchste) bis 255 (niedrigste) mit einem Standardwert von 127:

// Increase priority for interactive streams
stream.Priority = 64; // Higher priority than the default 127

Video MIME-Typkonstanten

Eine neue System.Net.Mime.MediaTypeNames.Video Klasse stellt Zeichenfolgenkonstanten für allgemeine Videomedientypen bereit:

  • MediaTypeNames.Video.Mp4"video/mp4"
  • MediaTypeNames.Video.Mpeg"video/mpeg"
  • MediaTypeNames.Video.Ogg"video/ogg"
  • MediaTypeNames.Video.QuickTime"video/quicktime"
  • MediaTypeNames.Video.WebM"video/webm"

Diese verbinden die vorhandenen MediaTypeNames.Application, , MediaTypeNames.Image, MediaTypeNames.Textund MediaTypeNames.Multipart Klassen.

Unsicherer API-Zugriff

.NET 11 entfernt das attribut [RequiresUnsafe] aus einem großen Satz von APIs, die Zeigerparameter verwenden. Zuvor erforderte das Aufrufen dieser Methoden aus Code, der unsafe-Blöcke verwendete, weiterhin eine <AllowUnsafeBlocks>true</AllowUnsafeBlocks>-Einstellung auf Projektebene, da das Attribut diese Anforderung unabhängig davon durchsetzte. Jetzt ist nur noch der Standard-unsafe-Block oder Methodenmodifizierer erforderlich.

Zu den betroffenen APIs gehören:

Diese Änderung verringert den Aufwand in fortgeschrittenen Szenarien wie der Erstellung von Interoperabilitätscode, speicherzugeordneten Dateien und der Manipulation von Puffern auf niedriger Ebene, wenn vom aufrufenden Code ohnehin bereits ein unsafe-Kontext erforderlich ist.

Siehe auch