Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo descrive le nuove funzionalità nelle librerie di .NET per .NET 11. L'ultimo aggiornamento è stato eseguito per l'anteprima 7.
Diagnostica ed esecuzione di processi
Espansione dell'API Process
Process include un set sostanziale di nuove API che coprono scenari comuni in cui in precedenza era necessario collegare OutputDataReceived/ErrorDataReceived gli eventi manualmente o usare P/Invoke.
Utilità di esecuzione e acquisizione
Le nuove API one-shot consentono di avviare un processo e ottenere il risultato senza configurare manualmente:
// 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}");
Il set completo di helper include:
- Process.Run e Process.RunAsync — avviare un processo e restituire il risultato dello stato di uscita.
- Process.RunAndCaptureText e Process.RunAndCaptureTextAsync : avviare e acquisire stdout/stderr insieme al codice di uscita.
- Process.ReadAllText(Nullable<TimeSpan>), Process.ReadAllBytes(Nullable<TimeSpan>)e le relative varianti asincrone: leggere l'output standard di un processo figlio in una singola chiamata.
- Process.ReadAllLines(Nullable<TimeSpan>) — legge in modo sincrono tutte le righe di output da un processo figlio, restituendo una sequenza di ProcessOutputLine valori che distinguono stdout da stderr.
- Process.ReadAllLinesAsync(CancellationToken) — restituisce un flusso di ProcessOutputLine valori che distinguono stdout da stderr senza l'analisi di stringhe.
Missili spara e dimentica
- Process.StartAndForget — avvia un processo figlio quando non si intende aspettare; il runtime scollega automaticamente l'handle.
- ProcessStartInfo.StartDetached — si scollega dalla sessione o dalla console dell'elemento padre in modo che il figlio possa uscire da un terminale.
- ProcessStartInfo.KillOnParentExit (solo per Windows) — il processo figlio viene terminato quando il processo padre termina.
Metodi del ciclo di vita SafeProcessHandle
SafeProcessHandle acquisisce metodi del ciclo di vita per scenari avanzati:
- SafeProcessHandle.Start(ProcessStartInfo) e una nuova proprietà SafeProcessHandle.ProcessId: avviare e identificare i processi senza passare attraverso Process stesso.
- SafeProcessHandle.Kill() e SafeProcessHandle.Signal(PosixSignal) : terminano o segnalano un processo tramite handle.
- SafeProcessHandle.WaitForExit() e SafeProcessHandle.WaitForExitAsync(CancellationToken) — attendere la terminazione di un processo mediante handle.
Controllo più preciso dell'impugnatura
-
ProcessStartInfo.InheritedHandles — specifica esattamente quali handle del sistema operativo vengono ereditati da un processo figlio, invece di usare l'impostazione predefinita tutto o niente
UseShellExecute = false. - ProcessStartInfo.StandardInputHandle, ProcessStartInfo.StandardOutputHandle e ProcessStartInfo.StandardErrorHandle — forniscono valori Microsoft.Win32.SafeHandles.SafeFileHandle già aperti per il reindirizzamento senza che il framework ne apra di nuovi.
Avvii sospesi e ricerca dei processi
System.Diagnostics.Process aggiunge un controllo più corretto sull'avvio e la ricerca dei processi:
- ProcessStartInfo.StartSuspendedavvia un processo in stato sospeso in Windows e macOS. Abbinalo a SafeProcessHandle.Resume() per farlo eseguire una volta completata l'eventuale configurazione iniziale, ad esempio collegando un debugger o configurando oggetti di processo.
-
Process.TryGetProcessById(Int32, Process) restituisce
falseanziché generare quando non esiste alcun processo con l'ID specificato. - <xref:Microsoft.Win32.SafeHandles.SafeProcessHandle.Open(System.Int32)> e <xref:Microsoft.Win32.SafeHandles.SafeProcessHandle.TryOpen(System.Int32,Microsoft.Win32.SafeHandles.SafeProcessHandle@)> aprire un handle per un processo esistente in base all'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();
Supporto di FORCE_COLOR nella console
L'output della console .NET supporta ora lo standard FORCE_COLOR oltre all'esistente supporto per NO_COLOR. Quando FORCE_COLOR è impostato, Console.IsOutputRedirected non elimina più i codici di escape ANSI. Ciò è utile quando si reindirizza tramite pipe l'output di dotnet run attraverso tee, a un visualizzatore di log CI o tramite less -R:
FORCE_COLOR=1 dotnet run | tee build.log
Adattatori di flussi di dati in memoria
Quattro nuovi tipi Stream incapsulano i comuni dati in memoria, così puoi passarli a qualsiasi API che si aspetta un Stream, senza copiarli prima in un MemoryStream:
-
ReadOnlyMemoryStreamespone un oggettoReadOnlyMemory<byte>come flusso di sola lettura. -
WritableMemoryStreamespone un oggetto scrivibileMemory<byte>come flusso a dimensione fissa. -
ReadOnlySequenceStreamespone un oggettoReadOnlySequence<byte>(ad esempio, buffer daSystem.IO.Pipelines) come flusso senza appiattirlo. -
StringStreamlegge unstringoReadOnlyMemory<char>come un flusso utilizzando una codifica specificata.
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 è particolarmente utile con System.IO.Pipelines, perché trasmette direttamente sui segmenti di un ReadOnlySequence<byte> anziché allocare una copia contigua.
Gestione di testo, serializzazione e dati
- Miglioramenti delle stringhe e dei caratteri
- Miglioramenti della codifica Base64
- Convalida UTF e ricerca di sottosequenza non valida
- Miglioramenti di System.Text.Json
- Miglioramenti delle espressioni regolari
Miglioramenti delle stringhe e dei caratteri
.NET 11 introduce miglioramenti significativi alle API di manipolazione di stringhe e caratteri, semplificando l'uso di caratteri e rune Unicode.
Supporto di Rune nei metodi String
La String classe include ora metodi che accettano Rune parametri, consentendo di cercare, sostituire e modificare le stringhe usando direttamente i valori scalari Unicode. Questi nuovi metodi includono:
-
Contains- Controllare se una stringa contiene una runa specifica: String.Contains(Rune) e String.Contains(Rune, StringComparison). -
StartsWithandEndsWith- Controllare se una stringa inizia o termina con una runa specifica: String.StartsWith(Rune), String.StartsWith(Rune, StringComparison)String.EndsWith(Rune), e String.EndsWith(Rune, StringComparison). -
IndexOfandLastIndexOf- Trovare la posizione di una runa in una stringa: String.IndexOf(Rune), String.IndexOf(Rune, StringComparison), String.LastIndexOf(Rune)e String.LastIndexOf(Rune, StringComparison). -
Replace- Sostituire tutte le ricorrenze di una runa con un'altra: String.Replace(Rune, Rune). -
Split- Dividere una stringa usando una runa come separatore: String.Split(Rune, StringSplitOptions) e String.Split(Rune, Int32, StringSplitOptions). -
Trim,TrimStarteTrimEnd- Taglia le esecuzioni dalle stringhe: String.Trim(Rune), String.TrimStart(Rune)e String.TrimEnd(Rune).
Molti di questi metodi includono overload che accettano un StringComparison parametro per confronti che tengono conto delle impostazioni cultura.
Metodo Char.Equals con StringComparison
La Char struct ora include un Char.Equals(Char, StringComparison) metodo che accetta un StringComparison parametro, consentendo di confrontare i caratteri usando confronti ordinali o basati sulla cultura.
Supporto di Rune in TextInfo
La classe TextInfo ora fornisce i metodi TextInfo.ToLower(Rune) e TextInfo.ToUpper(Rune) che accettano parametri Rune, consentendo di eseguire conversioni di maiuscole/minuscole su singoli valori scalari Unicode.
StringBuilder.MoveChunks
Per trasferire il contenuto senza copiare caratteri, usare il nuovo metodo statico StringBuilder.MoveChunks(StringBuilder) , che sposta tutto il contenuto da un'origine StringBuilder a un nuovo StringBuilderoggetto . Dopo la chiamata, l'origine StringBuilder ha una lunghezza pari a 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
Miglioramenti della codifica Base64
.NET 11 aggiunge nuove API e sovraccarichi al tipo Base64 esistente, fornendo supporto completo per la codifica e la decodifica in Base64. Queste aggiunte offrono prestazioni e flessibilità migliori rispetto ai metodi esistenti.
Nuove API Base64
Le nuove API supportano le operazioni di codifica e decodifica con vari formati di input e output:
- Codifica in caratteri: EncodeToChars e EncodeToString
- Codifica in UTF-8: EncodeToUtf8
- Decodifica da caratteri: DecodeFromChars
- Decodifica da UTF-8: DecodeFromUtf8
Questi metodi forniscono metodi pratici di alto livello (che allocano e restituiscono matrici o stringhe) e metodi basati su intervalli di basso livello (per scenari di allocazione zero).
Convalida UTF e ricerca di sottosequenza non valida
System.Text.Unicode ha due nuove funzionalità complementari.
Utf16.IsValid(ReadOnlySpan<Char>) risponde se una sequenza è ben formata UTF-16 senza scansione due volte e Utf8.IndexOfInvalidSubsequence(ReadOnlySpan<Byte>) / Utf16.IndexOfInvalidSubsequence(ReadOnlySpan<Char>) restituisce la posizione della prima sequenza di codice in formato non corretto (o -1 per l'input valido). Insieme, questi metodi consentono ai parser, ai validator e ai serializzatori di segnalare errori precisi anziché messaggi di errore di codifica generici.
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
Miglioramenti di System.Text.Json
Recupero informazioni tipo generico
Un modello comune quando si utilizzano System.Text.Json metadati di tipo consiste nel recuperare un JsonTypeInfo<T> da JsonSerializerOptions.
In precedenza, era necessario eseguire manualmente il downcast dal metodo non generico GetTypeInfo(Type).
I nuovi metodi generici JsonSerializerOptions.GetTypeInfo<T>() e JsonSerializerOptions.TryGetTypeInfo<T>(JsonTypeInfo<T>) restituiscono direttamente metadati fortemente tipizzati, eliminando il cast.
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;
}
Ciò è particolarmente utile quando si lavora con gli scenari di generazione di origine, NativeAOT e serializzazione polimorfica in cui l'accesso ai metadati dei tipi è comune.
Denominare e ignorare impostazioni predefinite
Le opzioni di denominazione e di esclusione disponibili in System.Text.Json ora includono:
- JsonNamingPolicy.PascalCase: nuovo criterio di denominazione predefinito che converte i nomi delle proprietà in PascalCase. Unisce i criteri camelCase, snake_case e kebab-case esistenti.
- Criterio di denominazione per membro: il nuovo System.Text.Json.Serialization.JsonNamingPolicyAttribute attributo consente di eseguire l'override dei criteri di denominazione per singole proprietà o campi, offrendo un controllo con granularità fine senza un convertitore personalizzato.
- Condizioni di ignorare a livello di tipo: l'applicazione System.Text.Json.Serialization.JsonIgnoreAttribute a livello di classe o struct imposta il comportamento di ignorare predefinito per tutti i membri, quindi non è più necessario ripetere l'attributo in ogni proprietà nullable.
// 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
Supporto dell'unione discriminata F#
Il serializzatore ora gestisce nativamente le unioni discriminate di F#. Le app che condividono tipi tra produttori F# e consumer C# non necessitano più di un convertitore personalizzato per le forme più comuni:
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 usando le opzioni
Reset ora accetta un parametro JsonWriterOptions, quindi le istanze di writer possono essere reintegrate nel pool con opzioni diverse senza allocare una nuova istanza di writer:
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 });
Miglioramenti di SerializeAsyncEnumerable
JsonSerializer.SerializeAsyncEnumerable ottiene due nuove funzionalità:
-
PipeWritertarget: Per gli scenari di I/O basati su pipeline, i nuovi overload accettano un PipeWriter come destinazione di output, semplificando l'integrazione diretta dello streaming JSON. -
topLevelValuesparametro: per l'output NDJSON, impostare questo parametro sutrueper scrivere ogni elemento come valore JSON di primo livello separato da nuove righe anziché eseguire il wrapping di tutti gli elementi in una matrice JSON. Entrambi i sovraccarichiStreamePipeWritersupportano il parametro.
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);
Serializzazione dei tipi di unione C#
System.Text.Json ora può serializzare e deserializzare i tipi di unione C#. Il serializzatore riconosce un'unione tramite il nuovo JsonTypeInfoKind.Union tipo di contratto, legge e scrive il caso attivo e supporta sia il serializzatore basato sulla riflessione sia il generatore di codice sorgente. Quando si serializza un'unione, System.Text.Json scrive il valore del caso attivo, quindi un'unione di int e string viene serializzata e deserializzata senza problemi:
{
"id": 1,
"payload": "hello"
}
{
"id": 2,
"payload": 42
}
Le nuove API JsonUnionAttribute e JsonUnionCaseInfo, insieme alle API di classificazione dei tipi (JsonTypeClassifier e JsonSerializerOptions.TypeClassifiers), consentono di personalizzare il modo in cui i casi vengono individuati e denominati. I tipi di unione sono una funzionalità di anteprima del linguaggio C#. Per altre informazioni, vedere Novità di C# 15.
Inferenza del polimorfismo per gerarchia chiusa
JsonSerializerOptions aggiunge JsonSerializerOptions.InferClosedTypePolymorphism in modo che il serializzatore possa dedurre metadati polimorfici per le gerarchie chiuse C# senza richiedere annotazioni esplicite JsonDerivedTypeAttribute su ogni tipo di base. Le registrazioni esplicite hanno ancora la precedenza.
Miglioramenti delle espressioni regolari
Opzione AnyNewLine
Un nuovo RegexOptions.AnyNewLine flag rende ^, $e . considera il set completo di caratteri di nuova riga Unicode come caratteri di terminazione di riga, non solo \n. Ciò consente di analizzare il testo che combina Windows (\r\n), Unix (\n) e le terminazioni di riga specifiche di Unicode (\u0085, \u2028, \u2029).
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
Correzioni del motore regex e del generatore di origine
.NET 11 include diverse correzioni regex e correzioni di qualità del codice:
- Il motore senza backtracking non impiega più un tempo superlineare in determinati schemi di cicli annidati e produce risultati corretti nei casi che in precedenza portavano a divergenza.
- Il compilatore di espressioni regolari e il generatore di codice sorgente gestiscono correttamente
resumeAtquando un costrutto condizionale compare all'interno del corpo di un ciclo. - L'SYSLIB1045 correzione del codice non crea più nomi di classe duplicati quando vengono applicati in più dichiarazioni parziali della stessa classe.
Formati di compressione e archiviazione
Miglioramenti della compressione
.NET 11 include diversi miglioramenti alle API di compressione.
Modalità di accesso agli elementi dell'archivio ZIP
La ZipArchiveEntry classe supporta ora l'apertura di voci con modalità di accesso ai file specifiche tramite nuovi overload: ZipArchiveEntry.Open(FileAccess) e ZipArchiveEntry.OpenAsync(FileAccess, CancellationToken). Queste sovraccarichi accettano un parametro FileAccess e consentono di aprire file ZIP per l'accesso di lettura, di scrittura o di lettura/scrittura.
Inoltre, una nuova CompressionMethod proprietà espone il metodo di compressione usato per un elemento tramite l'enumerazione ZipCompressionMethod, che include i valori per Stored, Deflate e Deflate64.
Validazione CRC32 di ZIP
ZipArchive verifica il checksum CRC32 durante la lettura degli elementi dell’archivio ZIP. Gli archivi danneggiati o troncati passati in precedenza senza errori ora generano InvalidDataException, consentendo di rilevare tempestivamente i problemi di integrità dei dati.
Supporto per password di archivi ZIP
ZipArchiveEntry ora supporta elementi protetti da password per le operazioni di lettura e scrittura. Usa i nuovi overload con supporto per password ZipArchiveEntry.Open(ReadOnlySpan<Char>) e ZipEncryptionMethod, e usa password e ZipArchiveEntry.OpenAsync(ReadOnlySpan<Char>, CancellationToken) quando crei voci criptate.
Modifica del comportamento DeflateStream e GZipStream
A partire da .NET 11, DeflateStream e GZipStream scrivono sempre le intestazioni e i piè di pagina del formato nel flusso di output, anche quando non viene scritto alcun dato. In questo modo l'output è un flusso compresso valido in base alle specifiche Deflate e GZip.
In precedenza, questi flussi non producevano alcun output se non è stato scritto alcun dato, generando un flusso di output vuoto. Questa modifica garantisce la compatibilità con gli strumenti che prevedono flussi compressi formattati correttamente.
Per ulteriori informazioni, vedere DeflateStream e GZipStream scrivono intestazioni e piè di pagina per payload vuoti.
API Deflate, ZLib e GZip basate su Span
System.IO.Compression ora offre Span<byte>/ReadOnlySpan<byte> punti di ingresso codificati e decodificati per i formati Deflate, ZLib e GZip. Le nuove API, per tipi come DeflateEncoder, ZLibEncoder e GZipEncoder, rispecchiano la struttura di BrotliEncoder/BrotliDecoder e delle primitive Zstandard. È possibile comprimere e decomprimere i buffer senza allocare un oggetto Stream. Questo è utile in scenari ad alta velocità di elaborazione, come parser di protocolli, strumenti di inoltro dei log e middleware che operano già su span.
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}");
Compressione Zstandard
Le API di compressione Zstandard, ad esempio ZstandardStream e ZstandardEncoder, ora fanno parte del namespace System.IO.Compression, insieme a DeflateStream, GZipStream e BrotliStream. La superficie dell'API è in caso contrario invariata.
Selezione del formato archivio Tar
Nuovi sovraccarichi su CreateFromDirectory e CreateFromDirectoryAsync accettano un parametro TarEntryFormat, offrendo il controllo diretto sul formato di archivio. In precedenza, CreateFromDirectory produceva sempre archivi Pax. I nuovi overload supportano tutti e quattro i formati tar( Pax, Ustar, GNU e V7) per la compatibilità con strumenti e ambienti specifici.
// 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 può ora anche leggere le voci che utilizzano la rappresentazione del formato GNU sparse 1.0 (PAX). La rappresentazione 0.1 precedente era già supportata. Con il supporto 1.0 abilitato, TarReader corrisponde a ciò che le moderne implementazioni di tar scrivono per impostazione predefinita per i file sparsi.
Raccolte, numeri e I/O di basso livello
- Miglioramenti del join in LINQ
- Tipi decimali in virgola mobile IEEE 754
- Analisi numerica parziale
- Generic Complex<T>
- Supporto di BFloat16 in BitConverter
- Formattazione e analisi esadecimale a virgola mobile
- Miglioramenti numerici
- Metodi generici casuali
- Operazioni vettoriali tra lane
- Miglioramenti di I/O di basso livello
- Miglioramenti delle raccolte
Miglioramenti all'aggiunta a LINQ
LINQ aggiunge miglioramenti ai join, tra cui una nuova operazione FullJoin e overload che restituiscono tuple per i metodi Join e GroupJoin esistenti. Queste API sono disponibili in Enumerable, Queryablee AsyncEnumerable.
LeftJoin, RightJoin e FullJoin
Poiché le tre operazioni di join esterno restituiscono direttamente tuple, è possibile utilizzarle facilmente tramite la corrispondenza di pattern e la decostruzione:
-
Enumerable.LeftJoin — Restituisce tutti gli elementi dalla sequenza sinistra (esterna). Quando non è presente alcun elemento corrispondente nella sequenza di destra (interna), l'elemento interno è
default(in generenullper i tipi di riferimento). -
Enumerable.RightJoin — Restituisce tutti gli elementi dalla sequenza destra (interna). Quando non è presente alcun elemento corrispondente nella sequenza di sinistra (esterna), l'elemento della sequenza esterna è
default(in generenullper i tipi di riferimento). -
Enumerable.FullJoin — Restituisce tutti gli elementi di entrambe le sequenze, utilizzando
defaultsu entrambi i lati quando non esiste alcuna corrispondenza.
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
Tipi in virgola mobile decimale IEEE 754
System.Numerics aggiunge Decimal32, Decimal64 e Decimal128, che implementano la semantica in virgola mobile decimale IEEE 754-2019. Questi tipi supportano valori matematici, infiniti e NaN generici e possono essere utili quando è necessario un comportamento decimale IEEE anziché Decimal.
Analisi numerica parziale
INumberBase<TSelf>.TryParsePartial aggiunge overload di analisi parziali che segnalano l'input utilizzato. Usare questa API per analizzare i formati delimitati, ad esempio CSV, in modo da non copiare sottostringhe.
Generico complesso<T>
Complex<T>è ora disponibile, quindi un'aritmetica complessa può usare diversi tipi a virgola mobile, tra cui float, HalfBFloat16, e i nuovi tipi a virgola mobile decimali.
Overload di Join e GroupJoin che restituiscono tuple
I nuovi sovraccarichi di Enumerable.Join e Enumerable.GroupJoin restituiscono tuple direttamente senza richiedere un selettore di risultato e accettano un parametro facoltativo IEqualityComparer<T>. L'overload facoltativo del comparatore è disponibile anche per le operazioni FullJoin, LeftJoin e RightJoin.
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
Supporto di BFloat16 in BitConverter
La BitConverter classe include ora metodi per la conversione tra BFloat16 valori e matrici di byte o rappresentazioni di bit. Questi nuovi metodi includono:
- BitConverter.GetBytes(BFloat16) - Convertire un valore BFloat16 in una matrice di byte.
- BitConverter.ToBFloat16(Byte[], Int32) e BitConverter.ToBFloat16(ReadOnlySpan<Byte>) - Convertire un array di byte in un valore BFloat16.
-
BitConverter.BFloat16ToInt16Bits(BFloat16), BitConverter.BFloat16ToUInt16Bits(BFloat16), BitConverter.Int16BitsToBFloat16(Int16)e BitConverter.UInt16BitsToBFloat16(UInt16) - Metodi per la conversione tra BFloat16 e la relativa rappresentazione di bit come
shortoushort.
BFloat16 (Brain Floating Point) è un formato a virgola mobile a 16 bit comunemente usato nell'apprendimento automatico e nel calcolo scientifico.
Formattazione e analisi esadecimale a virgola mobile
double, floate Half ora possono essere formattati e analizzati nel formato IEEE-754 esadecimale. La forma esadecimale preserva ogni bit del valore sottostante, il che la rende la scelta giusta per i test con golden file, l'interoperabilità tra linguaggi con C/C++ printf("%a", ...) e qualsiasi scenario in cui il passaggio di andata e ritorno di un double tramite testo decimale comporta una perdita eccessiva.
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
Miglioramenti numerici
Matrix4x4.GetDeterminant() ora usa un'implementazione con vettorizzazione SSE, migliorando le prestazioni di circa 15%.
Metodi generici casuali
Random ottiene due nuovi metodi generici che funzionano con qualsiasi tipo numerico che implementa le interfacce matematiche generiche appropriate:
-
Random.NextInteger — Genera un numero intero casuale di tipo
Tin cuiTimplementaIBinaryInteger<T>eIMinMaxValue<T>. Gli overload accettano un limite superiore oppure sia un limite inferiore sia un limite superiore. -
Random.NextBinaryFloat — Genera un valore a virgola mobile casuale di tipo
Tin cuiTimplementaIBinaryFloatingPointIeee754<T>.
// 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}");
Operazioni vettoriali tra lane
Vector64<T>, Vector128<T>, Vector256<T>Vector512<T>, e Vector<T> ottengono un set di metodi di costruzione e composizione di corsie che in precedenza richiedevano shuffle scritti a mano. I nuovi metodi rientrano in alcune famiglie:
-
Costruzione con pattern:
CreateGeometricSequence,CreateAlternatingSequenceeCreateHarmonicSequencecompila un vettore da un valore iniziale e una regola. -
Interleave e de-interleave:
Zip,ZipLower/ZipUpper,Unzip,UnzipEven/UnzipOdd. -
Riorganizzare: Famiglia
Concat(ConcatLowerLower,ConcatLowerUpper,ConcatUpperLower,ConcatUpperUpper) eReverse.
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));
Questi blocchi predefiniti sono utili per l'elaborazione di immagini, l'elaborazione dei segnali audio digitali (DSP) e altri carichi di lavoro a elevato utilizzo di SIMD che richiedono un controllo granulare sul layout degli elementi vettoriali, senza tornare a intrinseci specifici della piattaforma.
Miglioramenti di I/O di basso livello
Supporto della pipe SafeFileHandle
SafeFileHandle ottiene due nuovi membri:
- SafeFileHandle.Type property: segnala se un handle rappresenta un file, una pipe, un socket, una directory o un altro oggetto del sistema operativo, senza richiedere codice specifico della piattaforma.
- SafeFileHandle.CreateAnonymousPipe(SafeFileHandle, SafeFileHandle, Boolean, Boolean) Metodo: crea una coppia di handle di pipe anonimi connessi con un comportamento asincrono indipendente per ogni estremità.
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
}
Supporto della pipe di accesso casuale
RandomAccess.Read e RandomAccess.Write ora funzionano con handle non ricercabili, ad esempio pipe, oltre ai normali handle di file.
Su Windows, Process ora utilizza operazioni di I/O sovrapposte per stdout/stderr reindirizzati, riducendo il blocco del pool di thread nelle applicazioni ad alto utilizzo di processi.
Miglioramenti delle raccolte
BitArray.PopCount
La BitArray classe include ora un BitArray.PopCount() metodo che restituisce il numero di bit impostati su true nella matrice. In questo modo è possibile contare i bit impostati in modo efficiente senza scorrere manualmente la matrice.
Supporto di IReadOnlySet nella serializzazione JSON
La JsonMetadataServices classe include ora un JsonMetadataServices.CreateIReadOnlySetInfo metodo, abilitando il supporto della serializzazione JSON per IReadOnlySet<T> le raccolte.
EqualityComparer<T>.Create
Per creare un comparatore di uguaglianza da una funzione di selezione della chiave, usare il nuovo metodo factory EqualityComparer<T>.Create. È possibile passare un valore facoltativo IEqualityComparer<T> per il tipo di chiave stesso:
// 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
Estensioni e piattaforma per sviluppatori
- Scaffolding delle unioni discriminate
- Aggiunte a MetadataLoadContext
- Miglioramenti alla riflessione
- Override di Assembly.Location per AssemblyLoadContext
- Riduzione della contesa in System.IO.Pipelines
- Costante dello schema dati URI
- Miglioramenti dell'attributo StringSyntax
Generazione di codice per unioni con discriminante
Note
Questa è una funzionalità di anteprima in .NET 11.
.NET 11 introduce System.Runtime.CompilerServices.UnionAttribute e System.Runtime.CompilerServices.IUnion in System.Runtime.CompilerServices. Questi tipi sono il lato runtime della progettazione di unioni discriminate C#. Non sono ancora esposti direttamente agli utenti — il compilatore C# e i generatori di codice sorgente dovrebbero essere i principali elementi che li producono — ma sono inclusi nel framework affinché le librerie possano sviluppare già da ora rispetto a questa superficie API.
Per la progettazione sul lato linguaggio, vedere la proposta di unioni C#.
Novità di MetadataLoadContext
MetadataLoadContext.GetLoadContext(Assembly) restituisce il contesto di caricamento che ha prodotto un determinato Assembly, rispecchiando l'API esistente da tempo in AssemblyLoadContext. In questo modo si chiude un divario per gli strumenti che riflettono gli assembly in un isolato MetadataLoadContext e deve tornare da un Assembly riferimento al contesto proprietario:
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
Costante dello schema dati URI
È stata aggiunta una nuova Uri.UriSchemeData costante che rappresenta lo data: schema URI. Questa costante fornisce un modo standardizzato per fare riferimento agli URI dei dati.
Miglioramenti alla riflessione
Type.GetNullableUnderlyingType
System.Type ottiene un nuovo metodo virtuale, Type.GetNullableUnderlyingType(), che restituisce il tipo di valore sottostante per un tipo Nullable<T>, o null per qualsiasi tipo che non ammette valori null. Le implementazioni vengono fornite in Type, TypeBuilderEnumBuilder, GenericTypeParameterBuilder, e 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() ora ha un override, fornendo un modo coerente per recuperare argomenti di tipo generico per le definizioni del costruttore, che corrispondono al comportamento già disponibile in altre MethodBase sottoclassi.
Override di Assembly.Location per AssemblyLoadContext
AssemblyLoadContext.SetAssemblyLocationOverride(Func<Assembly,String,String>) è un callback impostabile una sola volta che può sovrascrivere la posizione riportata da Assembly.Location. Questa API consente agli host che organizzano assembly in percorsi temporanei o posizioni virtualizzate di segnalare posizioni stabili e significative per la diagnostica e il codice di caricamento delle risorse.
Riduzione della contesa in System.IO.Pipelines
System.IO.Pipelines riduce la contenzione dei lock di lettura e scrittura nei carichi di lavoro con elevato fan-in. Le modifiche interne includono un ambito di blocco inferiore, la pianificazione della continuazione della coda locale e gli aggiornamenti del pool che migliorano la località della cache.
Miglioramenti dell'attributo StringSyntax
La StringSyntaxAttribute classe include ora costanti per i linguaggi di programmazione comuni:
- CSharp - Indica la sintassi C#.
- FSharp - Indica la sintassi F#.
- VisualBasic - Indica Visual Basic sintassi.
Queste costanti possono essere usate con l'attributo StringSyntax per fornire un migliore supporto degli strumenti per i valori letterali stringa contenenti codice in questi linguaggi.
Memorizzazione nella cache, configurazione e registrazione
- Associazione di configurazione
- Metriche di MemoryCache OpenTelemetry
- Miglioramenti alla convalida del generatore di opzioni
- ChangeToken.OnChange asincrono
- Factory HybridCache con riconoscimento delle opzioni
- Convalida asincrona con DataAnnotations
- Configurazione del tracciamento delle attività
- Metodi generici di registrazione generati dal codice sorgente
- Maggiore affidabilità per il rilevamento delle modifiche ai file di configurazione
Legame di configurazione
Microsoft.Extensions.Configuration aggiunge Microsoft.Extensions.Configuration.ConfigurationIgnoreAttribute, così i modelli possono escludere singole proprietà dal binding in modo dichiarativo, senza basarsi su opzioni BindNonPublicProperties o convertitori personalizzati:
public sealed class AppOptions
{
public string Endpoint { get; set; } = "";
[ConfigurationIgnore]
public string ComputedKey => Endpoint + ":default";
}
ConfigurationBinder associa ora anche una matrice vuota a un parametro del costruttore anziché generare un'eccezione.
PhysicalFilesWatcher non genera più quando la directory radice non esiste ancora e InMemoryDirectoryInfo risolve .. e altri segmenti relativi in modo coerente con il provider fisico.
Metriche di MemoryCache OpenTelemetry
MemoryCache ora genera un set predefinito di metriche compatibili con OpenTelemetry (OTel) senza un pacchetto di adattatori aggiuntivo. Per attivare questa opzione, impostare MemoryCacheOptions.TrackStatistics su true:
var cache = new MemoryCache(new MemoryCacheOptions
{
TrackStatistics = true
});
Il nuovo contatore Microsoft.Extensions.Caching.Memory.MemoryCache pubblica quattro strumenti osservabili:
-
dotnet.cache.requests(con undotnet.cache.request.typetag che distinguehitdamiss) dotnet.cache.evictionsdotnet.cache.entriesdotnet.cache.estimated_size
Passa un System.Diagnostics.Metrics.IMeterFactory al nuovo sovraccarico del costruttore MemoryCache.MemoryCache(IOptions<MemoryCacheOptions>, ILoggerFactory, IMeterFactory) per metriche specifiche dell'istanza. Senza uno, gli strumenti sono aggregati a livello di processo su un contatore condiviso.
Miglioramenti alla convalida del generatore di opzioni
OptionsBuilder<TOptions> ottiene un nuovo overload generico OptionsBuilder<TOptions>.Validate che accetta un parametro di tipo anziché un delegato factory. Il tipo deve implementare IValidateOptions<TOptions> ed essere registrato nel contenitore di dependency injection. Ciò allinea la validazione delle opzioni al pattern DI standard:
services.AddSingleton<IValidateOptions<MyOptions>, MyOptionsValidator>();
services.AddOptions<MyOptions>()
.Bind(configuration.GetSection("MyOptions"))
.Validate<MyOptionsValidator>();
ChangeToken.OnChange asincrono
OnChange ora dispone di Func<Task> sovraccarichi, quindi puoi eseguire callback asincrone senza usare async void. La nuova registrazione avviene ora dopo il completamento dell'attività restituita.
Factory HybridCache con riconoscimento delle opzioni
GetOrCreateAsync ora dispone di overload che forniscono un contesto factory modificabile. È possibile impostare le opzioni per la singola voce, ad esempio la scadenza e la dimensione della cache locale, dal callback che produce valori.
Convalida asincrona con DataAnnotations
System.ComponentModel.DataAnnotations supporta ora la convalida asincrona. Una regola di convalida che deve eseguire operazioni di I/O, ovvero una ricerca di database o una chiamata API remota, può ora essere eseguita senza bloccare un thread. Esistono tre nuovi modi per esprimere una regola asincrona:
- Derivare da
AsyncValidationAttributeed eseguire l'override del relativoIsValidAsyncmetodo. - Implementare
IAsyncValidatableObjectnel modello. - Chiamare i nuovi
Validator.ValidateObjectAsyncmetodi ,TryValidateObjectAsyncValidatePropertyAsync, eValidateValueAsync.
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 aggiunge il supporto per la corrispondenza: le opzioni possono essere validate in modo asincrono, anche all'avvio tramite il nuovo IAsyncStartupValidator. In questo modo, un'app fallisce subito se un'opzione che richiede un controllo di rete è configurata in modo errato.
Configurazione del tracciamento attività
Una nuova API di configurazione del tracciamento in Microsoft.Extensions.Diagnostics consente di attivare e disattivare il tracciamento Activity con regole anziché configurare manualmente istanze di ActivityListener. Chiamare AddTracing e descrivere le origini attività, le operazioni e i listener da abilitare o disabilitare. Le regole possono essere definite tramite configurazione, in modo che il tracciamento possa essere regolato senza effettuare una nuova distribuzione.
builder.Services.AddTracing(tracing =>
{
tracing.EnableTracing(sourceName: "MyCompany.Orders");
tracing.DisableTracing(sourceName: "MyCompany.Orders", operationName: "HealthCheck");
});
La stessa release aggiunge ActivitySourceFactory e rende disponibile ActivitySource, che insieme consentono la creazione tramite factory e listener aggiornabili.
Metodi generici di registrazione generati dal codice sorgente
Il generatore di codice sorgente per la registrazione ora supporta metodi generici contrassegnati con LoggerMessageAttribute, principalmente per evitare il boxing. I parametri di tipo generico possono usare vincoli standard, ad esempio class, struct, unmanaged, interfacce, tipi di base e new(). L'allows ref struct anti-vincolo non è supportato e produce 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;
Maggiore affidabilità per il rilevamento delle modifiche ai file di configurazione
Il PhysicalFilesWatcher tipo, usato dai provider di configurazione per rilevare le modifiche apportate ai file di configurazione, include diversi miglioramenti dell'affidabilità.
Ora gestisce in modo più affidabile i percorsi relativi, le directory mancanti e i file system che non supportano il monitoraggio dei file. Evita inoltre di controllare le sottodirectory quando non è necessario.
Cryptography
Scambio di chiavi X25519 Diffie-Hellman
La nuova System.Security.Cryptography.X25519DiffieHellman classe astratta fornisce un'API pulita per l'algoritmo di Diffie-Hellman curva ellittica X25519, ampiamente usato nelle implementazioni TLS 1.3, SSH e Signal-protocol. Le implementazioni specifiche della piattaforma vengono fornite tramite X25519DiffieHellmanCng (Windows) e X25519DiffieHellmanOpenSsl (Linux e macOS), ma il metodo factory portabile GenerateKey() seleziona automaticamente quello corretto:
// 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
La classe supporta il ciclo di vita completo della chiave: generazione di chiavi, PKCS#8 e SubjectPublicKeyInfo import/export, serializzazione PEM e accesso a chiavi private/pubbliche non elaborate.
Overload di CryptographicOperations.FixedTimeEquals
Per gli scenari di confronto di segreti in cui il valore previsto è un singolo byte noto, utilizzare il nuovo sovraccarico CryptographicOperations.FixedTimeEquals che confronta ReadOnlySpan<T> con un singolo valore byte a tempo costante:
bool equal = CryptographicOperations.FixedTimeEquals(receivedSpan, 0x42);
Sicurezza delle reti e dei trasporti
- Protezione avanzata dell'handshake TLS
- Compressione delle richieste HTTP
- Rimozione configurabile delle connessioni HTTP
- API di risoluzione dei record DNS
- Downgrade automatico di HTTP/2 per l'autenticazione di Windows
- Priorità del flusso QUIC
- Costanti del tipo MIME video
Protezione avanzata dell'handshake TLS
Due System.Net.Security elementi migliorano l'affidabilità di TLS (Transport Layer Security):
-
SslStream correzioni al controllo dei limiti nell'handshake lato server in
TlsFrameHelperrisolvono diversi casi limite che potrebbero manifestarsi comeIOExceptionnei record ClientHello malformati. - Su Linux, gli errori di convalida dei certificati vengono ora segnalati al peer come allerte TLS standard, in linea con il comportamento di Windows. I client che si connettono ricevono un messaggio di errore di handshake che consente di intervenire, invece di un'interruzione della connessione.
Compressione delle richieste HTTP
System.Net.Http aggiunge i wrapper GZipCompressedContent, BrotliCompressedContent e ZstandardCompressedContent per i corpi delle richieste. Questi wrapper impostano l'intestazione Content-Encoding e trasmettono in streaming contenuto compresso durante la serializzazione della richiesta.
Eliminazione configurabile delle connessioni HTTP
SocketsHttpHandler ora fornisce SocketsHttpHandler.ShouldEvictConnection per le decisioni di espulsione per ogni connessione. Questo callback consente di ritirare le connessioni in base all'età, ai dettagli dell'endpoint e alle modifiche DNS anziché ai criteri fissi di sola durata.
API di risoluzione dei record DNS
System.Net.Dns aggiunge API tipizzate per la risoluzione dei record, tra cui Dns.ResolveSrv(String), Dns.ResolveMx(String), Dns.ResolveTxt(String), Dns.ResolveCName(String), Dns.ResolvePtr(String) e Dns.ResolveNs(String), insieme alle varianti Async. I risultati includono record, codice di risposta e metadati TTL (Negative-Cache Time to Live) tramite DnsResult<T>.
Declassamento automatico di HTTP/2 per l'autenticazione di Windows
HttpClient effettua automaticamente il downgrade a HTTP/1.1 quando una richiesta richiede autenticazione di Windows (NTLM/Negotiate) su HTTP/2. La specifica HTTP/2 non consente gli schemi di autenticazione associati alla connessione su cui si basa NTLM e Kerberos, quindi queste richieste in precedenza non sono riuscite. Con il downgrade applicato, le applicazioni destinate agli ambienti con autenticazione mista, comuni nelle intranet aziendali, funzionano senza override espliciti HttpRequestMessage.Version.
Priorità del flusso QUIC
QuicStream ottiene una QuicStream.Priority proprietà e una QuicStream.DefaultPriority costante che espone la priorità del flusso HTTP/3 (RFC 9218). I valori di priorità sono compresi tra 0 (massimo) e 255 (più basso), con un valore predefinito pari a 127:
// Increase priority for interactive streams
stream.Priority = 64; // Higher priority than the default 127
Costanti del tipo MIME video
Una nuova System.Net.Mime.MediaTypeNames.Video classe fornisce costanti stringa per i tipi di supporti video comuni:
-
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"
Queste classi vengono unite alle classi , MediaTypeNames.ApplicationMediaTypeNames.Image, e MediaTypeNames.Text esistentiMediaTypeNames.Multipart.
Accessibilità dell'API non sicura
.NET 11 rimuove l'attributo [RequiresUnsafe] da un ampio set di API che accettano parametri puntatore. In precedenza, la chiamata di questi metodi dal codice che usava unsafe blocchi richiedeva ancora un'impostazione a livello <AllowUnsafeBlocks>true</AllowUnsafeBlocks> di progetto perché l'attributo imponeva tale requisito in modo indipendente. A questo punto, è necessario solo il modificatore di blocco o metodo standard unsafe .
Le API interessate includono:
- Buffer.MemoryCopy
- ReadOnlySpan<T>.ReadOnlySpan<T>(Void*, Int32) e Span<T>.Span<T>(Void*, Int32)
-
System.Runtime.CompilerServices.Unsafe metodi del puntatore come
AsRef,Read,WriteeCopy - Metodi System.Runtime.InteropServices.NativeMemory
- System.Text.Encoding overload del puntatore (tutte le classi di codifica)
-
System.Numerics.Vector metodi basati su
LoadpuntatoriStore - Tipi di marshalling di interoperabilità in System.Runtime.InteropServices.Marshalling
Questa modifica riduce le difficoltà in scenari avanzati, ad esempio la scrittura di codice di interoperabilità, i file mappati in memoria e la manipolazione di buffer di basso livello, in cui il contesto unsafe è già richiesto dal codice chiamante.