.NET 11 - Preview 1 - Novidades nas bibliotecas base
As bibliotecas do .NET 11 ganharam um pacote generoso de APIs novas logo no Preview 1, lançado pela Microsoft em 10 de fevereiro de 2026. Neste artigo, apresento cada novidade com exemplos de código e com o contexto de uso que justifica a sua chegada.
O objetivo aqui não é apenas listar o que mudou. Por isso, para cada recurso, explico como ele funciona, por que foi adicionado e em quais cenários reais ele faz diferença.
Visão geral das bibliotecas do .NET 11 Preview 1
O .NET 11 é a versão STS (Standard Term Support) prevista para novembro de 2026, sucedendo o .NET 10 LTS. Assim, tudo o que aparece neste preview ainda pode mudar até o lançamento final.
As notas de versão oficiais das bibliotecas listam mais de vinte itens. Neste texto, concentro a análise nos que têm maior impacto no dia a dia de quem escreve APIs, serviços e ferramentas.
No vídeo abaixo, comento as principais novidades deste primeiro preview.
Compressão Zstandard nas bibliotecas do .NET 11
A compressão de dados sempre foi crítica em aplicações modernas, sobretudo quando a largura de banda é limitada ou o armazenamento custa caro. Historicamente, porém, o .NET oferecia suporte nativo apenas a GZip, Deflate, ZLib e, mais tarde, Brotli.
O algoritmo Zstandard
O Zstandard, ou Zstd, é um algoritmo criado no Facebook (hoje Meta) que combina alta velocidade com uma boa taxa de compressão. Em testes preliminares com payloads JSON de 200 MB, observei reduções da ordem de 30% em relação ao GZip, com tempos de processamento equivalentes.
Os benchmarks oficiais da equipe do .NET vão na mesma direção. Segundo as notas de versão, o Zstandard comprime de 2 a 7 vezes mais rápido que Brotli e Deflate no nível Optimal e descomprime de 2 a 14 vezes mais rápido no nível Fastest.
Como usar o ZstandardStream
O Preview 1 traz as classes ZstandardStream, ZstandardEncoder e ZstandardDecoder. Além disso, a API segue o mesmo formato de GZipStream e BrotliStream, o que facilita a migração de código existente.
using System.IO.Compression;
public static class ZstdHelper
{
// Comprime um array de bytes com Zstandard
public static async Task<byte[]> CompressAsync(byte[] data)
{
using var output = new MemoryStream();
await using (var zstd = new ZstandardStream(output, CompressionMode.Compress))
{
await zstd.WriteAsync(data);
}
return output.ToArray();
}
// Descomprime os dados de volta
public static async Task<byte[]> DecompressAsync(byte[] compressed)
{
using var input = new MemoryStream(compressed);
await using var zstd = new ZstandardStream(input, CompressionMode.Decompress);
using var output = new MemoryStream();
await zstd.CopyToAsync(output);
return output.ToArray();
}
}
Para quem precisa de controle fino, a classe ZstandardCompressionOptions expõe nível de qualidade, tamanho de janela, checksum e long distance matching. Do mesmo modo, existe suporte a compressão baseada em dicionário.
var options = new ZstandardCompressionOptions
{
Quality = 5,
WindowLog = 22,
AppendChecksum = true,
EnableLongDistanceMatching = true
};
using var stream = new ZstandardStream(outputStream, options);
Descompressão automática no HttpClient
O HttpClient também passou a reconhecer respostas com Content-Encoding: zstd. Para isso, basta incluir o novo valor DecompressionMethods.Zstandard no handler.
var handler = new HttpClientHandler
{
// Aceita respostas em GZip e em Zstandard
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Zstandard
};
using var client = new HttpClient(handler);
var response = await client.GetAsync("https://example.com/api/orders");
Quando escolher Zstandard
APIs que servem grandes volumes de JSON se beneficiam bastante da taxa de compressão. Da mesma forma, sistemas de logging e telemetria ganham ao comprimir dados antes de enviá-los para um armazenamento central.
No entanto, a escolha depende do contexto. Quando a compatibilidade com clientes legados é crítica, o GZip ainda pode ser a opção mais segura, como discuto no artigo sobre compressão de respostas no ASP.NET Core.
BFloat16 nas bibliotecas do .NET 11
O crescimento das aplicações de machine learning trouxe demandas por tipos numéricos otimizados. Nesse cenário, o tipo System.Numerics.BFloat16 (Brain Floating Point) chega como uma solução que equilibra precisão e eficiência.
Características do BFloat16
O BFloat16 ocupa 16 bits, mas distribui esses bits de forma diferente do Half. Ele mantém 8 bits de expoente, como o float, e apenas 7 bits de mantissa.
Essa escolha privilegia o alcance dinâmico em vez da precisão, que é exatamente o que modelos de IA costumam exigir.
Por isso, o tipo é comum em GPUs e aceleradores de treinamento. Além disso, o tipo implementa as interfaces numéricas genéricas, como INumber<BFloat16> e IBinaryFloatingPointIeee754<BFloat16>.
Nas bibliotecas do .NET 11, o suporte vai além do próprio tipo. Por exemplo, BitConverter, BinaryPrimitives, BigInteger e Complex também ganharam APIs para lidar com BFloat16, e a contribuição veio do membro da comunidade @huoyaoyuan.
using System.Buffers.Binary;
using System.Numerics;
public sealed class NeuralLayer
{
private readonly BFloat16[] _weights;
public NeuralLayer(int size)
{
_weights = new BFloat16[size];
for (var i = 0; i < size; i++)
{
// Conversão explícita de float para BFloat16
_weights[i] = (BFloat16)(Random.Shared.NextSingle() * 2f - 1f);
}
}
public BFloat16 Activate(ReadOnlySpan<BFloat16> inputs)
{
var sum = BFloat16.Zero;
for (var i = 0; i < _weights.Length; i++)
{
sum += _weights[i] * inputs[i];
}
return sum;
}
// Serializa um valor em little endian
public static void Write(Span<byte> buffer, BFloat16 value) =>
BinaryPrimitives.WriteBFloat16LittleEndian(buffer, value);
}
Benefícios e limitações
A principal vantagem é a redução de 50% no uso de memória em relação ao float, com alcance dinâmico praticamente idêntico. Com isso, cabem modelos maiores na mesma RAM e o cache da CPU é melhor aproveitado.
Por outro lado, a precisão reduzida não serve para todos os cenários. Cálculos financeiros ou científicos que exigem exatidão devem continuar com float, double ou decimal.
ZipArchiveEntry nas bibliotecas do .NET 11
Quem trabalha com arquivos ZIP no .NET conhecia uma limitação incômoda do modo Update. Nesse modo, abrir uma entrada sempre carregava todo o conteúdo em memória, mesmo quando a intenção era apenas ler.
Abertura com FileAccess
O Preview 1 adiciona sobrecargas de ZipArchiveEntry.Open() que recebem um FileAccess. Dessa forma, você abre a entrada só para leitura e faz streaming sem carregar tudo na memória.
using System.IO.Compression;
using var archive = ZipFile.Open("backup.zip", ZipArchiveMode.Update);
var entry = archive.GetEntry("large-file.dat");
// Somente leitura: faz streaming sem carregar a entrada inteira
using var readStream = entry!.Open(FileAccess.Read);
// Também existe a versão assíncrona
await using var asyncStream = await entry.OpenAsync(FileAccess.Read);
Propriedade CompressionMethod
Além disso, a entrada agora expõe a propriedade CompressionMethod e o enum ZipCompressionMethod. Antes, a única forma de descobrir se um arquivo estava comprimido era comparar CompressedLength com Length.
foreach (var item in archive.Entries)
{
// Identifica arquivos armazenados sem compressão
if (item.CompressionMethod == ZipCompressionMethod.Stored)
{
Console.WriteLine($"{item.FullName} is stored without compression");
}
}
Para ferramentas de build, sistemas de backup e utilitários de sincronização, essas mudanças reduzem consumo de memória e eliminam heurísticas frágeis. A preservação de metadados, como o LastWriteTime de cada entrada, continua disponível pela API já existente.
FrozenDictionary com collection expressions
O FrozenDictionary surgiu no .NET 8 como uma coleção otimizada para leitura intensiva. Agora, nas bibliotecas do .NET 11, ele recebe o atributo [CollectionBuilder], o que habilita a sintaxe de dictionary expressions do C#.
using System.Collections.Frozen;
// Antes (.NET 8, 9 e 10)
var legacySettings = new Dictionary<string, string>
{
["ApiKey"] = "abc123",
["Endpoint"] = "https://api.example.com",
["Timeout"] = "30"
}.ToFrozenDictionary();
// Agora, com dictionary expression e comparer explícito
FrozenDictionary<string, int> lookup =
[with(StringComparer.Ordinal), "one": 1, "two": 2, "three": 3];
Com essa mudança, as bibliotecas do .NET 11 alinham o FrozenDictionary ao padrão que já valia para FrozenSet e ImmutableDictionary. Assim, configurações carregadas na inicialização, tabelas de mapeamento e caches que raramente mudam ficam mais simples de declarar.
Fusos horários nas bibliotecas do .NET 11
Trabalhar com fusos horários sempre foi complexo, porque regras de horário de verão mudam e países alteram seus fusos ao longo do tempo. Por isso, dados históricos precisam ser interpretados com as regras vigentes na época.
O Preview 1 introduz um cache por ano das transições de fuso, armazenadas em UTC. Segundo os benchmarks oficiais, conversões ficaram de 2,4 a 3,9 vezes mais rápidas no Windows e de 1,6 a 4,7 vezes mais rápidas no Linux.
Mais importante ainda, o novo caminho substitui a lógica antiga baseada em regras, que acumulava remendos. Com isso, vários bugs em que a conversão devolvia resultados incorretos foram corrigidos.
public static DateTime ToUtc(DateTime local, string timeZoneId)
{
var zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
// O offset considera as regras válidas para a data informada
var offset = zone.GetUtcOffset(local);
Console.WriteLine($"Offset for {local}: {offset}");
return TimeZoneInfo.ConvertTimeToUtc(local, zone);
}
Sistemas financeiros, plataformas de séries temporais e aplicações de auditoria ganham diretamente com essa correção, sem mudar uma linha de código.
Em outras palavras, esta é uma das melhorias das bibliotecas do .NET 11 que chegam de graça. Basta recompilar o projeto para net11.0 e as conversões já usam o novo cache.
Suporte a Rune nas bibliotecas do .NET 11
Unicode é mais complexo do que parece. Um caractere visual pode ocupar dois char (um surrogate pair), e a manipulação incorreta corrompe textos com emojis ou ideogramas.
O tipo Rune representa um único code point Unicode. Agora, as bibliotecas do .NET 11 levam o Rune para String, StringBuilder, TextWriter, TextInfo e Char.
using System.Text;
var text = "Hello 🌍 World";
var globe = new Rune(0x1F30D);
// Busca, substituição e divisão usando Rune
bool contains = text.Contains(globe);
string replaced = text.Replace(globe, new Rune('X'));
string[] parts = text.Split(globe);
// StringBuilder também entende Rune
var builder = new StringBuilder("Hello ");
builder.Append(globe);
foreach (Rune rune in builder.EnumerateRunes())
{
Console.Write(rune);
}
// TextWriter escreve Rune diretamente
Console.Out.Write(new Rune(0x4E2D));
Há ainda o novo struct RunePosition, que enumera runes em spans e informa a posição e o tamanho de cada uma. Portanto, editores de texto, validadores e ferramentas de processamento de linguagem natural passam a segmentar texto de forma confiável.
MediaTypeMap para tipos MIME
Aplicações web precisam descobrir o tipo MIME a partir da extensão do arquivo, seja para servir conteúdo estático, seja para validar uploads. Até aqui, isso exigia pacotes de terceiros ou dicionários mantidos à mão.
A nova classe System.Net.Mime.MediaTypeMap resolve o problema com os mapeamentos registrados na IANA e os mais comuns do Apache.
using System.Net.Mime;
public static class UploadValidator
{
private static readonly string[] AllowedTypes =
["image/jpeg", "image/png", "application/pdf", "text/plain"];
public static string ResolveContentType(string fileName) =>
// Retorna null quando a extensão é desconhecida
MediaTypeMap.GetMediaType(fileName) ?? "application/octet-stream";
public static void Validate(string fileName)
{
var contentType = ResolveContentType(fileName);
if (!AllowedTypes.Contains(contentType))
throw new InvalidOperationException($"File type not allowed: {contentType}");
}
}
O caminho inverso também existe, com MediaTypeMap.GetExtension("application/pdf"). Como a implementação é mantida pela Microsoft, os mapeamentos evoluem junto com o framework.
HMAC e KMAC nas bibliotecas do .NET 11
O HMAC é a base de muitos fluxos de integridade, como a assinatura de webhooks. Entretanto, o valor calculado precisa ser comparado em tempo constante, para evitar ataques de temporização.
Antes, o padrão exigia dois passos, e muita gente acabava usando SequenceEqual, que não é seguro. Agora, todas as classes HMAC e KMAC ganharam métodos Verify, que já fazem a comparação em tempo constante.
using System.Security.Cryptography;
using System.Text;
public sealed class WebhookAuthenticator(byte[] secretKey)
{
public string Sign(string payload)
{
var hash = HMACSHA256.HashData(secretKey, Encoding.UTF8.GetBytes(payload));
return Convert.ToBase64String(hash);
}
public bool IsValid(string payload, string receivedSignature)
{
var data = Encoding.UTF8.GetBytes(payload);
var expected = Convert.FromBase64String(receivedSignature);
// Comparação sempre em tempo constante
return HMACSHA256.Verify(secretKey, data, expected);
}
}
Existem ainda sobrecargas para streams, versões assíncronas e o método genérico CryptographicOperations.VerifyHmac. Em outras palavras, a forma correta passou a ser também a forma mais curta.
Essa é, na minha avaliação, uma das mudanças mais valiosas das bibliotecas do .NET 11. Afinal, um erro de comparação em validação de assinatura costuma passar despercebido em code review.
Criação de hard links
Hard links permitem que várias entradas de diretório apontem para os mesmos dados no disco. Até o .NET 10, criar um hard link exigia P/Invoke ou bibliotecas de terceiros.
O Preview 1 adiciona File.CreateHardLink e FileInfo.CreateAsHardLink. Diferente dos links simbólicos, eles não exigem privilégios de administrador no Windows, embora não atravessem volumes.
using System.Security.Cryptography;
public static class FileDeduplicator
{
public static void Deduplicate(string directory)
{
var groups = Directory.GetFiles(directory)
.GroupBy(ComputeHash)
.Where(group => group.Count() > 1);
foreach (var group in groups)
{
var master = group.First();
foreach (var duplicate in group.Skip(1))
{
// Remove a cópia e cria um hard link para o original
File.Delete(duplicate);
File.CreateHardLink(duplicate, master);
}
}
}
private static string ComputeHash(string path)
{
using var stream = File.OpenRead(path);
return Convert.ToHexString(SHA256.HashData(stream));
}
}
Sistemas de build, backups incrementais e gerenciadores de pacotes economizam espaço com essa técnica.
Contudo, tome cuidado com um detalhe importante. Como todos os links apontam para os mesmos dados, alterar o conteúdo por um caminho altera o arquivo visto por todos os outros.
DivisionRounding na divisão inteira
A divisão inteira em C# trunca o resultado em direção ao zero. Contudo, diferentes domínios exigem arredondamento para baixo, para cima, euclidiano ou para longe do zero.
O novo enum DivisionRounding e os métodos Divide, DivRem e Remainder em IBinaryInteger<T> resolvem isso com implementações otimizadas.
// Divisão padrão do C# trunca: -7 / 2 = -3
int truncated = int.Divide(-7, 2, DivisionRounding.Truncate); // -3
int floored = int.Divide(-7, 2, DivisionRounding.Floor); // -4
int ceiling = int.Divide(7, 2, DivisionRounding.Ceiling); // 4
// Resto euclidiano é sempre não negativo
int remainder = int.Remainder(-7, 3, DivisionRounding.Euclidean); // 2
// Quociente e resto de uma vez
var (quotient, rest) = int.DivRem(-7, 2, DivisionRounding.Floor); // -4 e 1
// Divide 10000 centavos entre 3 pessoas sem perder centavos
long totalCents = 10_000;
long share = long.Divide(totalCents, 3, DivisionRounding.Floor); // 3333
long leftover = totalCents - share * 3; // 1 centavo
Por exemplo, em sistemas de cobrança, você calcula a parcela base com Floor e distribui o resto centavo a centavo. Repare que a API atua sobre tipos inteiros, então valores monetários devem ser tratados em centavos.
Portanto, esse recurso das bibliotecas do .NET 11 elimina aquele cálculo manual com Math.Floor e conversões que sempre gerava dúvidas em números negativos.
Happy Eyeballs nas bibliotecas do .NET 11
Muitos servidores aceitam IPv4 e IPv6, mas nem toda rede tem IPv6 funcional. Nesse caso, uma tentativa de conexão via IPv6 pode gerar timeouts longos.
O algoritmo Happy Eyeballs, definido na RFC 8305, faz consultas DNS A e AAAA em paralelo e alterna tentativas entre os dois protocolos. O Preview 1 implementa isso no Socket.ConnectAsync com o novo enum ConnectAlgorithm.
using System.Net;
using System.Net.Sockets;
var args = new SocketAsyncEventArgs
{
RemoteEndPoint = new DnsEndPoint("example.com", 443)
};
// Usa Happy Eyeballs para conexões dual stack mais rápidas
Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, args, ConnectAlgorithm.Parallel);
Na prática, a conexão fica mais rápida em ambientes dual stack e mais resiliente a problemas de IPv6.
Vale notar que o HttpClient usa sockets por baixo dos panos. Ainda assim, as notas de versão das bibliotecas do .NET 11 descrevem o recurso no nível do Socket, por meio do valor ConnectAlgorithm.Parallel, e o comportamento padrão continua sendo ConnectAlgorithm.Default.
Outras APIs e ganhos de performance
As bibliotecas do .NET 11 Preview 1 também trazem itens menores, mas úteis. Entre eles estão o suporte a IReadOnlySet<T> no System.Text.Json, o Interlocked.And e Interlocked.Or genéricos e sobrecargas com CancellationToken no TextWriter.
Além disso, o HttpClient passou a aceitar proxies socks5h://, e o Base64 ganhou a mesma API rica do Base64Url.
Na performance, os destaques são:
Guid.NewGuid()cerca de 12% mais rápido no Linux, graças à syscallgetrandom();- multiplicação de
BigIntegercom o algoritmo Toom-Cook de três vias; TensorPrimitives.BitIncrementeBitDecrementvetorizados, até 3,8 vezes mais rápidos;Directory.GetFilescom filtro de padrão no nível do sistema operacional no Windows;- o novo
BitArray.PopCount(), acelerado por hardware.
Se você quer acompanhar a evolução, vale ler também as novidades do .NET 11 Preview 2 e o que mudou nas bibliotecas no Preview 3.
Como testar as bibliotecas do .NET 11
Para experimentar, instale o SDK do .NET 11 Preview 1 a partir da página oficial de download. Em seguida, ajuste o TargetFramework do projeto para net11.0.
Lembre que se trata de um preview. Portanto, use essas APIs em ambientes de desenvolvimento e teste, nunca em produção, e envie feedback pelo repositório do runtime.
Conclusão
As bibliotecas do .NET 11 Preview 1 representam um avanço concreto, focado em problemas que enfrentamos diariamente. O Zstandard atende à demanda por transferência eficiente, enquanto o BFloat16 reconhece o peso crescente do machine learning no ecossistema.
O suporte a Rune reflete um mundo cada vez mais multilíngue. Já as novas APIs de verificação HMAC mostram que segurança precisa estar no desenho da API, e não como reflexão tardia.
As otimizações de performance são menos visíveis, mas igualmente importantes. Cada alocação evitada e cada conversão de fuso mais rápida contribuem para aplicações mais responsivas.
Recomendo começar a explorar as bibliotecas do .NET 11 desde já, mesmo em projetos de estudo. Afinal, o feedback dado nesta fase ainda pode influenciar a forma final dessas APIs até novembro de 2026.
FAQ
O que há de novo nas bibliotecas do .NET 11 Preview 1?
Os destaques são Zstandard, BFloat16, Rune em strings, MediaTypeMap, verificação HMAC e KMAC, hard links, DivisionRounding e Happy Eyeballs. Também há ganhos de performance em fusos horários, Guid e BigInteger.
Preciso instalar um pacote NuGet para usar o Zstandard?
Não. As classes ZstandardStream, ZstandardEncoder e ZstandardDecoder fazem parte do próprio .NET 11.
O BFloat16 substitui o float?
Não. O BFloat16 serve para cargas de IA em que alcance importa mais que precisão, enquanto cálculos exatos continuam com float, double ou decimal.
O HMACSHA256.Verify é seguro contra timing attacks?
Sim. O método sempre compara os valores em tempo constante, o que elimina o erro comum de usar SequenceEqual.
Posso usar o .NET 11 Preview 1 em produção?
Não é recomendado. O .NET 11 só será lançado oficialmente em novembro de 2026, e as APIs ainda podem mudar.