.NET 11 Preview 3: Una revisión de un desarrollador
.NET 11 alcanza su tercera preview aproximadamente seis meses antes del GA planeado en noviembre de 2026, y a diferencia de Preview 1 y 2, que fueron principalmente de plomería, Preview 3 es aquel donde realmente puede sentir la forma del lanzamiento.
Runtime Async deja de ser un experimento de "puerta de características preliminares", el JIT obtiene otro lote de optimizaciones de dinero gratis, ASP.NET Core obtiene Zstandard de serie, y los tipos de unión de C# 15, la característica de lenguaje que la gente ha estado pidiendo durante casi una década.
Este no es un lanzamiento LTS, .NET 11 es la próxima versión de soporte estándar a término, con 24 meses de soporte, lo que ya cambia el cálculo de si actualizar. A continuación, lo que realmente vale su atención como desarrollador, y dónde aún están los bordes ásperos.
Tipos de Unión en C# 15: El Grande
Si has estado escribiendo bibliotecas OneOf<T1, T2>, creando jerarquías de registros sellados manualmente o simplemente envidiando a los desarrolladores de F#, este es el titular. C# 15 introduce una palabra clave de unión que declara que un valor es exactamente uno de un conjunto fijo de tipos, con exhaustividad aplicada por el compilador. Los tipos de unión llegaron en Preview 2; Preview 3 pule el soporte de IDE a su alrededor.
El enfoque del equipo de C# es más cercano a una unión de tipos que a las uniones discriminadas de F#: los tipos de miembros son tipos existentes que ha definido por separado, no casos de etiquetas anidados dentro de la declaración de unión. Una unión es esencialmente un struct que envuelve un objeto y limita lo que se puede introducir en él. Desde el sitio de llamada, se siente nativo: conversión implícita de tipos de miembros a la unión, expresiones switch exhaustivas sobre Pet.Value, y no se necesita un brazo predeterminado cuando el compilador puede ver todos los casos.
[Union]
public partial struct Pet : IUnion
{
public Pet(Dog dog);
public Pet(Cat cat);
public Pet(Bird bird);
}
string Describe(Pet pet) => pet.Value switch
{
Dog d => $"Dog named {d.Name}",
Cat c => $"Cat ({c.Color})",
Bird b => $"Bird, {b.Species}",
// no default - compiler knows the set is closed
};
[Union]
public partial struct Pet : IUnion
{
public Pet(Dog dog);
public Pet(Cat cat);
public Pet(Bird bird);
}
string Describe(Pet pet) => pet.Value switch
{
Dog d => $"Dog named {d.Name}",
Cat c => $"Cat ({c.Color})",
Bird b => $"Bird, {b.Species}",
// no default - compiler knows the set is closed
};
<Union>
Public Partial Structure Pet
Implements IUnion
Public Sub New(dog As Dog)
End Sub
Public Sub New(cat As Cat)
End Sub
Public Sub New(bird As Bird)
End Sub
End Structure
Function Describe(pet As Pet) As String
Return pet.Value Select Case
Case d As Dog
Return $"Dog named {d.Name}"
Case c As Cat
Return $"Cat ({c.Color})"
Case b As Bird
Return $"Bird, {b.Species}"
' no default - compiler knows the set is closed
End Select
End FunctionLas ventajas son reales: tipos cerrados, ningún estado inválido, exhaustividad en tiempo de compilación en lugar de NotImplementedExceptionat a las 3am. Agregue un Tiburón a la unión y cada switch sobre Pet se ilumina con advertencias hasta que lo maneje.
Los contras también son reales, y vale la pena señalarlos en cualquier revisión honesta. El propiedad de Valor de objeto expuesto es un olor: hay una discusión abierta en GitHub sobre ocultarlo detrás de algo más seguro para los tipos. Los constructores públicos definen implícitamente qué tipos acepta la unión, lo cual no es ni descubrible ni explícito. La interoperabilidad con F# no está resuelta (los dos modelos son fundamentalmente diferentes). Y la historia más amplia de exhaustividad aún tiene vacíos: jerarquías cerradas y enums cerrados, las dos propuestas que completarían el panorama, aún son propuestas. Las uniones por sí solas son geniales. Las uniones más enums cerrados más jerarquías cerradas serían un cambio generacional. Todavía no llegamos ahí.
Mejoras en la ejecución asincrónica en tiempo de ejecución V2 y JIT
La ejecución asincrónica en tiempo de ejecución es una reescritura silenciosa de .NET de cómo se ejecutan en realidad async/await. En lugar de que el compilador de C# emita una clase de máquina de estado por cada método asincrónico, el propio tiempo de ejecución gestiona la suspensión y la reanudación. La ventaja visible: trazas de pila más limpias, asignaciones más pequeñas y un depurador que no te hace desplazarte más allá de los marcos MoveNext para encontrar tu propio código.
En la Vista Previa 3, Runtime Async elimina el requisito de EnablePreviewFeatures. Todavía activas el interruptor de características - <Features>runtime-async=on</Features> - pero ya no tienes que optar cada llamada de API en territorio de vista previa. El soporte para NativeAOT y ReadyToRun también llegó en esta vista previa, lo que cierra la brecha entre los escenarios JIT y AOT. Los objetos de continuación se reutilizan de manera más agresiva, y las variables locales que no han cambiado no se guardan durante la suspensión. En rutas de código pesadas en asincronía - piensa en una tubería de Kestrel o un trabajador de consultas de EF Core - eso es una caída significativa en la presión de asignación.
JIT adquirió su lote habitual de "tu código existente ahora es más rápido, no hagas nada":
- Expresiones de conmutación multiobjetivo como x es 0 o 1 o 2 o 3 o 4 ahora se convierten en comprobaciones sin bifurcaciones.
- Las verificaciones de límites en patrones de valores[^1] + valores[^2] se eliminan de manera más agresiva, y el caso común de i + cns < len en los bucles colapsa limpiamente.
- Las conversiones de enteros sin signo a flotante y de enteros sin signo a doble son más rápidas en hardware x86 anterior a AVX-512, siendo algo de nicho, pero real si estás en cajas más antiguas.
Los usuarios de WebAssembly obtienen carga de payload WebCIL directamente en el runtime, mejores símbolos de depuración, y float[] / Span<float> / ArraySegment<float> marshaling sin la sobrecarga de ida y vuelta. Ninguna de estas es individualmente dramática, pero juntas son el tipo de trabajo compuesto que hace que Blazor WASM se sienta menos como un compromiso.
El problema es el umbral de hardware. .NET 11 eleva los requisitos mínimos del conjunto de instrucciones en x86/x64 y Arm64. Apple Silicon y la mayoría de las SBCs de Linux están bien - el objetivo de ReadyToRun en Arm64 solo agrega LSE - pero el hardware x86 muy antiguo está fuera. Audita tu flota antes de asumir una actualización in situ.
ASP.NET Core y Blazor
Zstandard es el titular aquí. ASP.NET Core ahora soporta zstd tanto para la compresión de respuestas como para la descompresión de solicitudes, y está habilitado por defecto cuando añades el middleware. La configuración tiene la forma que esperas:
builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
options.CompressionOptions = new ZstandardCompressionOptions { Quality = 6 };
});
builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
options.CompressionOptions = new ZstandardCompressionOptions { Quality = 6 };
});
Imports Microsoft.Extensions.DependencyInjection
builder.Services.AddResponseCompression()
builder.Services.AddRequestDecompression()
builder.Services.Configure(Of ZstandardCompressionProviderOptions)(Sub(options)
options.CompressionOptions = New ZstandardCompressionOptions With {.Quality = 6}
End Sub)Para las API que sirven cargas útiles JSON o de texto a clientes que ya hablan zstd - cada vez más común en ecosistemas móviles y adyacentes a gRPC - esto es una ganancia de ancho de banda medible sin depender de una biblioteca de terceros. Es también, notablemente, una contribución de la comunidad en lugar de una interna de Microsoft, lo que es una señal saludable.
El Virtualize<TItem> de Blazor finalmente deja de asumir que cada fila tiene la misma altura. Esto era una irritación de larga data: cualquier lista con contenido variable - comentarios, mensajes de chat, cualquier cosa con texto envuelto - necesitaba soluciones manuales. Ahora el componente mide los elementos en tiempo de ejecución. La versión Preview 3 también corrige una serie de errores de Blazor: una referencia nula en Virtualize, detección de scroll-container con overflow-x, la plantilla de Web Worker en apps WASM publicadas, casos límite de carga diferida TempData, y una pérdida de IJSObjectReference en ResourceCollectionProvider. Individualmente pequeños, colectivamente el tipo de limpieza que indica que el marco está madurando más allá de la fase "una nueva cosa en cada lanzamiento".
Kestrel también comienza a procesar solicitudes HTTP/3 sin esperar la corriente de control y el marco SETTINGS, lo que reduce la latencia de la primera solicitud en nuevas conexiones. Si has estado midiendo HTTP/3 P99s y viendo colas frías extrañas, esta es tu solución.
.NET MAUI
MAUI en la Vista Previa 3 trata en su mayor parte de cerrar brechas que han hecho que se sienta como una beta por demasiado tiempo. El control Map obtiene agrupación de pines, iconos de pines personalizados, estilo JSON personalizado y eventos de clic en círculos, polígonos y polilíneas, todas cosas que las interfaces de usuario de mapas en producción real necesitan y que antes requerían controladores personalizados por plataforma. Ahora está disponible un LongPressGestureRecognizer incorporado sin tener que crear uno propio. Las declaraciones implícitas de namespaces XAML están habilitadas por defecto, lo que reduce la plantilla al comienzo de cada archivo.
La paridad de plataforma recibe un impulso: Permissions.PostNotifications ahora se implementa en iOS (anteriormente era solo para Android), y Android obtiene soporte de vista previa para Android 17 y nivel de API 37.
La evaluación honesta: esta es una iteración constante y sensata, no una reinvención. MAUI en 2026 está en una posición mucho mejor que MAUI en 2023, pero si te alejaste de él antes en su vida, solo la Vista Previa 3 no te arrastrará de nuevo. Si ya estás en MAUI, estos son exactamente los cambios en la calidad de vida que deseas.
SDK, CLI, y .NET watch
Esta es la sección donde las pequeñas cosas se acumulan. Unas pocas que creo que realmente cambian el flujo de trabajo diario:
.NET sln ahora puede crear y editar filtros de solución (.slnf) directamente desde la CLI. Para monorepos y grandes soluciones al estilo de Microsoft, abrir un SLN de 200 proyectos para trabajar en tres de ellos ha sido un verdadero costo. Ahora puedes determinar el alcance desde el terminal:
dotnet new slnf --name MyApp.slnf
dotnet sln MyApp.slnf add src/Lib/Lib.csprojdotnet new slnf --name MyApp.slnf
dotnet sln MyApp.slnf add src/Lib/Lib.csprojLas aplicaciones basadas en archivos (el flujo de trabajo de app.cs de .NET run) finalmente admiten #:include, lo que significa que los scripts de C# pueden dividir ayudantes en archivos separados. Combinado con la finalización del editor para la directiva en Roslyn, esto empuja las aplicaciones basadas en archivos de "juguete" a "viables para herramientas de automatización reales" - el nicho que PowerShell y pequeños scripts de Python han poseído durante años.
.NET run -e FOO=BAR te permite pasar variables de entorno en la línea de comandos sin exportar el estado del shell ni editar perfiles de lanzamiento. Pequeño, pero si alguna vez has tenido tres terminales abiertos con diferentes valores ASPNETCORE_ENVIRONMENT, conoces el dolor.
.NET watch se integra con hosts de aplicaciones Aspire, se reinicia automáticamente después de un fallo en el próximo cambio de archivo, y maneja Ctrl+C de manera más elegante para WinForms y WPF (un corte perpetuo). .NET format acepta --framework para proyectos dirigidos a múltiples plataformas. .NET test en modo MTP admite --artifacts-path. Y .NET tool exec / dnx ya no solicita una aprobación adicional, lo que había sido un punto de fricción para ejecuciones de herramientas únicas.
Los puntos de dolor
Una revisión equilibrada debe los bordes ásperos, y la Vista Previa 3 los tiene.
La historia de las herramientas es áspera. Visual Studio 2026 aún está en vista previa seis meses después de que .NET 10 se lanzó, y los agentes de construcción hospedados por Microsoft todavía no tienen soporte estable para VS 2026. Un cambio en una versión de parche del SDK de .NET 10 requería MSBuild 18 (VS 2026), lo cual es una violación clara de las garantías semver que promueve Microsoft. Cualquiera que ejecute CI en agentes hospedados por Microsoft ha tenido que fijar el SDK 10.0.4 o cambiar a imágenes de construcción de vista previa. Si estás considerando mover las tuberías CI a las vistas previas de .NET 11, espera más de lo mismo - los SDK de vista previa han, según el propio equipo, roto cosas en 10.0.2 y 10.0.3 antes de estabilizarse.
La ejecución asincrónica en tiempo de ejecución todavía es opt-in. Incluso con la puerta de características de vista previa eliminada, tienes que activar runtime-async=on. Eso está bien para código de campo verde; para bibliotecas enviadas en NuGet, todavía no puedes asumir que tus consumidores tienen el interruptor activado, por lo que los beneficios prácticos se difieren hasta que la característica se active por defecto (no en .NET 11).
Incrementos en los requisitos de hardware. Los requisitos mínimos del conjunto de instrucciones x86/x64 aumentaron. La mayoría de los equipos no lo notarán. Algunos lo harán - y lo descubrirán en el momento del despliegue si no auditan primero.
STS, no LTS. .NET 11 es compatible por 24 meses. .NET 10, el LTS actual, recibe 36 meses. Para tiendas en cadencias de actualización lentas, .NET 10 sigue siendo la opción más conservadora, y adoptar .NET 11 significa comprometerse con otra actualización en 2028. El caso para adoptar un STS son las características; el caso en contra es el calendario.
Vista previa significa vista previa. Esto no es una crítica de estabilidad - el proceso de vista previa de Microsoft ha sido bueno - pero la Vista Previa 3 no es un candidato para lanzamiento. Las implementaciones de producción esperan el RC1 como muy pronto. Herramientas internas, proyectos secundarios y exploración son el alcance adecuado ahora.
Veredicto
Si escribes C# todos los días, vale la pena instalar y experimentar con la Vista Previa 3 de .NET 11 esta semana, particularmente para tener en tus manos los tipos de unión, que son el cambio de idioma más importante en años. Si mantienes bibliotecas, el trabajo de JIT y la ejecución asincrónica en tiempo de ejecución significa que tu código se volverá más rápido en .NET 11 sin ediciones, lo que es el mejor tipo de actualización. Si envías aplicaciones MAUI, el trabajo de Map y gesture es un progreso real.
Si ejecutas cargas de trabajo de .NET en producción, la respuesta es la aburrida: sigue planificando, sigue observando, y marca el GA en noviembre. Las piezas que emocionan están aterrizando, pero la cadena de herramientas - VS, agentes de construcción, y la cadencia de parches del SDK - es donde realmente vive la fricción, y no se ha solucionado todavía.
| --- |
Fuentes: Anuncio del blog de .NET, Novedades en .NET 11 (Microsoft Learn), Notas de lanzamiento de tiempo de ejecución, Notas de lanzamiento de ASP.NET Core, Notas de lanzamiento del SDK, Explorar tipos de unión en C# 15.
