El año pasado gustó mucho, así que vamos a preparar Otra sesión de Q&A. Si tienes cualquier pregunta, puedes dejarla en cualquiera de los 3 enlaces siguientes:
Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Novedades C# 14

20 Oct 2025 10 min (0) Comentarios

En una semanas tendremos el lanzamiento de la nueva versión de C# dentro de .NET 10. Pero vamos a ser unos early adopters y verlas y analizarlas ya. Por cierto si quieres acceder a ellas, puedes acceder a través de la versión preview que ya está disponible. Aunque no es recomendable utilizarlo en producción.

 

 

Por sexto año consecutivo, veamos las novedades que trae la nueva versión de C# 14.

 

 

1 - Asignador condicional Nulo

 

Hasta ahora en .NET siempre hemos tenido varias formas de indicar que el valor al que queremos acceder puede ser nulo. Una opcion es con el null-coalescing operator, que al final no deja de ser un if.

Person p = person ?? new Person();

 

En la versión anterior de C# vimos como podemos acceder a valores nulos a través del interrogante, por ejemplo en el siguiente código

int? age = person?.Age;

El compilador sera quien haga el if por detrás para asegurarse de que el valor no es nulo.

 

Con el nuevo cambio, podemos aplicar la misma lógica pero a la hora de asignar valores, donde indicamos el interrogante ? y será el compilador quien por detras cree el if, así que a partir de C# 14 este código:

person?.Age = 18;

Es completamente válido, incluso si la variable person es null

 

Puedes leer el post completo que cree sobre el null conditional assigment aquí.

 

 

2 - la expresión nameof soporta unbound generic tyes

 

Otro de los cambios, aunque menor en este caso, es que la expresión nameof funciona para tipos genéricos que no tienen un tipo asociado. 

 

Todos hemos utilizado nameof(Type) alguna vez para imprimir un nombre o incluso el valor de un enum:

string value =  nameof(List<>); 

Esta expresión tenía una limitación evidente y es que no funcionaba con tipos genéricos que no indican el tipo interno por lo que la expresion nameof(List<>) daba un error.

En la nueva version de C# esta expresión es completamente posible y puede servirnos para tener mejor documentación o información en logs, errores, etc.

 

 

3 - Field keyword

 

Con la llegada de C# 14 llega una funcionalidad a través de una nueva keyword denominada field.

Con esta keyword vamos a poder crear lógica en nuestros getters y setters sin tener que utilizar un backing field para ello. 

 

Sabemos que actualmente en una clase si queremos poner algo de lógica debemos almacenar el valor real de forma manual dentro de un field privado, a este fiel se le llama backing field.

public class FieldPropExampleWithLogic
{
	
	//field
	private string _message;

	// property
	public string Message
	{
		get => _message;
		set
		{
			if (string.IsNullOrEmpty(value) || !char.IsUpper(value[0]))
			{
				throw new ArgumentException("the first letter must be uppercase");
			}
			_message = value;
		}
	}
}

 

Con la nueva keyword field, ya no tenemos que hacerlo de forma manual, y será el compilador quien cree ese backing field:

public class FieldKeywordExampleWithLogic
{
	public string Message
	{
		get => field;
		set
		{
			if (string.IsNullOrEmpty(value) || !char.IsUpper(value[0]))
			{
				throw new ArgumentException("the first letter must be uppercase");
			}
			field = value;
		}
	}
}

 

Lo cual es bueno ya que nos permite escribir menos código además de encapsular el field dentro del getter y setter por lo que no podemos modificarlo por error fuera del mismo. 

 

Puedes leer más sobre la nueva field keyword aquí.

 

 

4 - Más soporte para Span y ReadonlySpan

 

Hará unos 5 o 6 años el equipo de C# incluyó un nuevo tipo Span, el cual se introdujo para acceder al stack de forma rápida y segura de datos que son contiguos como arrays, strings, o slices sin tener que copiarlos etc. (sólo vídeo) ahora que lo pienso, no tengo un vídeo sobre Span y quizá debería hacer uno. Pero bueno, el tema con 

 

Este nuevo cambio soporta conversiones implícitas como podemos ver a continuación

string[] words = ["Hello", "World"];
ReadOnlySpan<string> span = words;

 

En este ejemplo estamos convirtiendo un array en un span<T> de forma automática, lo que permite menos verbosidad a la hora de programar sin arriesgar liarla y armar un cristo en la memoria. 

 

 

5 - User defined compound assignment

 

Otro pequeño cambio relacionado con la memoria es la forma en la que el compound assignment funciona en C#.

 

El compound assignment es esta expresión : x+=y, lo que pasa por detrás es esto: x  = x+y; y cuando el operador + es llamado se crea un nuevo resultado y se asigna a la variable x. 

 

Con esta nueva funcionalidad podemos sobrescribir los operadores +=-=, ++ o -- directamente, esto permite incluir toda la lógica C# que quieras. 

 

Pero hay otro beneficio y es que si vamos por lo que la operación puede mutar el valor directamente en vez de crear un objeto nuevo.

public class E05_UserCompoundAssigment
{
    public void Test()
    {
        var x = new BigNumber(3)
        {
            Data = [1, 2, 3]
        };
        var y = new BigNumber(3)
        {
            Data = [10, 100, 1000]
        };

        x += y;
    }

    struct BigNumber
    {
        public int[] Data;

        public BigNumber(int size)
        {
            Data = new int[size];
        }

        public void operator += (BigNumber other)
        {
            for (int i = 0; i < Data.Length; i++)
                Data[i] += other.Data[i];
        }
    }
}

 

Es un caso de uso un poco nicho, pero estoy seguro que todos aquellos que trabajéis con grandes sets de datos que tienen que operar entre sí podréis ver una mejora al reducir el número de asignaciones en la memoria. 

 

 

6 - Extension members everywhere

 

En C#, desde hace tiempo hay métodos de extensión que permite “añadir” métodos a tipos existentes declarándose como métodos estáticos en una clase estática, usando this en el primer parámetro. 

 

Con la propuesta de extension members para C# 14, se permitirá usar una nueva sintaxis con la palabra clave extension para extender un tipo no solo con métodos, sino también con propiedades, indexadores y más, haciendo que esas extensiones parezcan miembros “normales” del tipo original

public static class MyExtensions
{
    extension(IEnumerable<int> source)
    {
        public IEnumerable<int> WhereGreaterThan(int threshold)
            => source.Where(x => x > threshold);

        public bool IsEmpty
            => !source.Any();
    }
}

 

Este cambio no quiere decir que tengas que cambiar tú código, pero personalmente veo valor en empezar a aplicarlo para código nuevo.

 

Puedes ver el análisis completo aquí.

 

 

 

7 - Funcionalidades que no están en C# 14

 

Como cada año, voy a mencionar aquellas funcionalidades que no están listas por unos motivos u otros  y que la comunidad pide desesperadamente

 

7.1 - Type Unions / Discriminated unions

 

Llevamos años pidiendo los union types y ya el año pasado teníamos un proposal para incluirlos, pero es más complejo de lo que puede parecer a simple vista y ya dijeron en una conferencia que seguramente se posponga para C#16 o C#17, así que veremos si el año que viene la tenemos en preview, lo que significa que estara casi seguro lista para C# 16 o tendremos que esperar más.

 

Podeis ver el proposal y cómo funcionará en GitHub.  

 

Y con este proposal quizá el result pattern se pueda implementar de forma nativa en C#

 

7.2 - Eventing framework nativo en C#

 

Desde hace un tiempo teníamos un proposal para implementar un framework sobre los eventos dentro de .NET para poder procesar mensajes con diferentes proveedores. Este proposal estaba pensado para ser lanzado en .NET9. 

 

Imagínate cualquiera de las nubes como EventBridge, SQS, EventBus, Kafka RabbitMQ, etc.

 

 

A mi personalmente me parece una idea cojonuda porque empresa a la que voy, empresa que tiene su propia abstracción sobre lo mismo pero que funciona un poco diferente en cada empresa. En C# ya solucionamos este problema con los logs, donde con la interfaz Ilogger<T> puedes utilizar la implementación que te dé la gana.

 

 

Desafortunadamente debido al feedback de la comunidad y principalmente a los autores de librerías populares sobre este aspecto se ha decidido cancelar para no “causar interrupciones o solapamientos con el ecosistema” cosa que me parece, como poco, ridícula, ya que en los últimos años han sacado varias funcionalidades que literalmente han matado librerías.

 

No se cual es el motivo real, pero está claro que si no tiene que ver con Inteligencia artificial o con Aspire no interesa invertir mucho tiempo. 

 

Aquí puedes leer el proposal en github.

 


© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café

🎨 Nueva Interfaz Disponible

¡Estamos probando una nueva interfaz con estilo Neo Brutalismo!

Esta es una versión en desarrollo que incluye:

  • ✨ Diseño moderno y audaz
  • 🎯 Mejor experiencia visual
  • 📱 Interfaz más limpia

¿Cómo activarla?

Añade ?useNewUI=true al final de cualquier URL

Ejemplo: https://netmentor.es?useNewUI=true

¿Cómo volver a la versión anterior?

Añade ?useNewUI=false al final de cualquier URL

⚠️ Esta es una versión en progreso. Algunos elementos pueden no funcionar perfectamente.