Rediger

What's new in .NET libraries for .NET 11

This article describes new features in the .NET libraries for .NET 11. It was last updated for Preview 3.

String and character enhancements

.NET 11 introduces significant enhancements to string and character manipulation APIs, making it easier to work with Unicode characters and runes.

Rune support in String methods

The String class now includes methods that accept Rune parameters, enabling you to search, replace, and manipulate strings using Unicode scalar values directly. These new methods include:

Many of these methods include overloads that accept a StringComparison parameter for culture-aware comparisons.

Char.Equals with StringComparison

The Char struct now includes an Char.Equals(Char, StringComparison) method that accepts a StringComparison parameter, allowing you to compare characters using culture-aware or ordinal comparisons.

Rune support in TextInfo

The TextInfo class now provides TextInfo.ToLower(Rune) and TextInfo.ToUpper(Rune) methods that accept Rune parameters, enabling you to perform case conversions on individual Unicode scalar values.

Base64 encoding improvements

.NET 11 adds new APIs and overloads to the existing Base64 type, providing comprehensive support for Base64 encoding and decoding. These additions offer improved performance and flexibility compared to existing methods.

New Base64 APIs

The new APIs support encoding and decoding operations with various input and output formats:

These methods provide both high-level convenience methods (that allocate and return arrays or strings) and low-level span-based methods (for zero-allocation scenarios).

Compression enhancements

.NET 11 includes several improvements to compression APIs.

ZIP archive entry access modes

The ZipArchiveEntry class now supports opening entries with specific file access modes through new overloads: ZipArchiveEntry.Open(FileAccess) and ZipArchiveEntry.OpenAsync(FileAccess, CancellationToken). These overloads accept a FileAccess parameter and allow you to open ZIP entries for read, write, or read-write access.

Additionally, a new CompressionMethod property exposes the compression method used for an entry through the ZipCompressionMethod enum, which includes values for Stored, Deflate, and Deflate64.

ZIP CRC32 validation

Starting in Preview 3, ZipArchive validates the CRC32 checksum when reading ZIP entries. Corrupted or truncated archives that previously passed without error now throw InvalidDataException, helping you detect data integrity issues early.

DeflateStream and GZipStream behavior change

Starting in .NET 11, DeflateStream and GZipStream always write format headers and footers to the output stream, even when no data is written. This ensures the output is a valid compressed stream according to the Deflate and GZip specifications.

Previously, these streams didn't produce any output if no data was written, resulting in an empty output stream. This change ensures compatibility with tools that expect properly formatted compressed streams.

For more information, see DeflateStream and GZipStream write headers and footers for empty payload.

BFloat16 support in BitConverter

The BitConverter class now includes methods for converting between BFloat16 values and byte arrays or bit representations. These new methods include:

BFloat16 (Brain Floating Point) is a 16-bit floating-point format that's commonly used in machine learning and scientific computing.

Collections improvements

BitArray.PopCount

The BitArray class now includes a BitArray.PopCount() method that returns the number of bits set to true in the array. This provides an efficient way to count set bits without manually iterating through the array.

IReadOnlySet support in JSON serialization

The JsonMetadataServices class now includes a JsonMetadataServices.CreateIReadOnlySetInfo method, enabling JSON serialization support for IReadOnlySet<T> collections.

URI data scheme constant

A new Uri.UriSchemeData constant has been added, representing the data: URI scheme. This constant provides a standardized way to reference data URIs.

StringSyntax attribute enhancements

The StringSyntaxAttribute class now includes constants for common programming languages:

These constants can be used with the StringSyntax attribute to provide better tooling support for string literals containing code in these languages.

System.Text.Json improvements

Generic type info retrieval

A common pattern when working with System.Text.Json type metadata is to retrieve a JsonTypeInfo<T> from JsonSerializerOptions. Previously, you had to manually downcast from the non-generic GetTypeInfo(Type) method. New generic JsonSerializerOptions.GetTypeInfo<T>() and JsonSerializerOptions.TryGetTypeInfo<T>(JsonTypeInfo<T>) methods return strongly typed metadata directly, eliminating the 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;
}

This is particularly useful when working with source generation, NativeAOT, and polymorphic serialization scenarios where type metadata access is common.

Naming and ignore defaults

Preview 3 expands the naming and ignore options available in System.Text.Json:

  • JsonNamingPolicy.PascalCase: A new built-in naming policy that converts property names to PascalCase. It joins the existing camelCase, snake_case, and kebab-case policies.
  • Per-member naming policy: The new [JsonNamingPolicy] attribute lets you override the naming policy on individual properties or fields, giving you fine-grained control without a custom converter.
  • Type-level ignore conditions: Applying [JsonIgnore(Condition = ...)] at the class or struct level sets the default ignore behavior for all members, so you no longer need to repeat the attribute on every nullable property.
// 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

Zstandard compression

The Zstandard compression APIs are now part of the System.IO.Compression namespace, alongside DeflateStream, GZipStream, and BrotliStream. If you referenced the earlier preview package, remove the separate package reference:

-<PackageReference Include="System.IO.Compression.Zstandard" />

The API surface is otherwise unchanged.

Tar archive format selection

New overloads on CreateFromDirectory and CreateFromDirectoryAsync accept a TarEntryFormat parameter, giving you direct control over the archive format. Previously, CreateFromDirectory always produced Pax archives. The new overloads support all four tar formats—Pax, Ustar, GNU, and V7—for compatibility with specific tools and environments.

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

Numerics improvements

Matrix4x4 performance

Matrix4x4.GetDeterminant() now uses an SSE-vectorized implementation, improving performance by approximately 15%.

Low-level I/O improvements

SafeFileHandle pipe support

SafeFileHandle gains two new members in Preview 3:

  • Type property: Reports whether a handle represents a file, pipe, socket, directory, or other OS object, without requiring platform-specific code.
  • CreateAnonymousPipe method: Creates a pair of connected anonymous pipe handles with independent async behavior for each end.
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 support

RandomAccess.Read and RandomAccess.Write now work with non-seekable handles such as pipes, in addition to regular file handles.

On Windows, Process now uses overlapped I/O for redirected stdout/stderr, which reduces thread-pool blocking in process-heavy applications.

Regular expression improvements

AnyNewLine option

A new RegexOptions flag, AnyNewLine, makes ^, $, and . treat the full set of Unicode newline characters as line terminators—not just \n. This helps when parsing text that mixes Windows (\r\n), Unix (\n), and Unicode-specific (\u0085, \u2028, \u2029) line endings.

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

See also