Novedades de C# 11

Se agregaron las siguientes características en C# 11:

C# 11 es compatible con .NET 7. Para obtener más información, vea Control de versiones del lenguaje C#.

Puede descargar el SDK de .NET 7 más reciente de la página de descargas de .NET. También puede descargar Visual Studio 2022, que incluye el SDK de .NET 7.

Nota

Estamos interesados en sus comentarios sobre estas características. Si encuentra problemas con cualquiera de estas nuevas características, cree un nuevo problema en el repositorio dotnet/roslyn.

Atributos genéricos

Puede declarar una clase genérica cuya clase base sea System.Attribute. Esta característica proporciona una sintaxis más cómoda para los atributos que requieren un parámetro System.Type. Antes había que crear un atributo que tomara Type como parámetro de constructor:

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;

   public Type ParamType { get; }
}

Y, para aplicar el atributo, se usa el operador typeof:

[TypeAttribute(typeof(string))]
public string Method() => default;

Con esta nueva característica, puede crear un atributo genérico en su lugar:

// C# 11 feature:
public class GenericAttribute<T> : Attribute { }

Luego, especifique el parámetro de tipo para usar el atributo:

[GenericAttribute<string>()]
public string Method() => default;

Debe proporcionar todos los parámetros de tipo al aplicar el atributo. En otras palabras, el tipo genérico debe construirse completamente. En el ejemplo anterior, los paréntesis vacíos (( y )) se pueden omitir, ya que el atributo no tiene ningún argumento.

public class GenericType<T>
{
   [GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
   public string Method() => default;
}

Los argumentos de tipo deben cumplir las mismas restricciones que el operador typeof. No se permiten los tipos que requieren anotaciones de metadatos. Por ejemplo, no se permiten los siguientes tipos como parámetro de tipo:

  • dynamic
  • string? (o cualquier tipo de referencia que acepte valores NULL)
  • (int X, int Y) (o cualquier otro tipo de tupla que use la sintaxis de tupla de C#)

Estos tipos no se representan directamente en los metadatos Incluyen anotaciones que describen el tipo. En todos los casos, se puede usar el tipo subyacente en su lugar:

  • object para dynamic
  • string en lugar de string?.
  • ValueTuple<int, int> en lugar de (int X, int Y).

Compatibilidad matemática genérica

Hay varias características de lenguaje que habilitan la compatibilidad matemática genérica:

  • static virtual miembros en interfaces
  • Operador definido por el usuario checked
  • operadores de desplazamiento relajado
  • Operador de desplazamiento a la derecha sin signo

Puede agregar static abstract o static virtual miembros en interfaces para definir interfaces que incluyan operadores sobrecargables, otros miembros estáticos y propiedades estáticas. El escenario principal de esta característica es usar operadores matemáticos en tipos genéricos. Por ejemplo, puede implementar la interfaz de System.IAdditionOperators<TSelf, TOther, TResult> en un tipo que implementa operator +. Otras interfaces definen otras operaciones matemáticas o valores bien definidos. Puede obtener información sobre la nueva sintaxis en el artículo sobre interfaces. Las interfaces que incluyen métodos de static virtual suelen ser interfaces genéricas. Además, la mayoría declarará una restricción que el parámetro de tipo implementa en la interfaz declarada.

Para más información y probar la característica usted mismo, consulte el tutorial Exploración de miembros de la interfaz abstracta estática o la entrada de blog Características en versión preliminar de .NET 6: matemáticas genéricas.

Las matemáticas genéricas han creado otros requisitos en el lenguaje.

  • Operador de desplazamiento a la derecha sin signo: antes de C# 11, para forzar un desplazamiento a la derecha sin signo, había que convertir cualquier tipo entero con signo en un tipo sin signo, llevar a cabo el desplazamiento y, después, convertir el resultado en un tipo con signo. A partir de C# 11, puede usar >>>, el operador de desplazamiento sin signo.
  • Requisitos de operador de desplazamiento menos estrictos: C# 11 elimina el requisito de que el segundo operando debe ser un int o convertible implícitamente en int. Este cambio permite que los tipos que implementan interfaces matemáticas genéricas se usen en estas ubicaciones.
  • Operadores definidos por el usuario checked y unchecked: los desarrolladores ya pueden definir los operadores aritméticos checked y unchecked. El compilador genera llamadas a la variante correcta en función del contexto actual. Puede obtener más información sobre los checkedoperadores en el artículo sobre operadores aritméticos.

IntPtr y UIntPtr numéricos

Los tipos nint y nuint ahora se conocen como System.IntPtr y System.UIntPtr respectivamente.

Nuevas líneas en interpolaciones de cadenas

El texto dentro de los caracteres { y } de una interpolación de cadenas ahora puede abarcar varias líneas. El texto entre los marcadores { y } se analiza como C#. Se permite cualquier C# válido, incluidas las nuevas líneas. Esta característica facilita la lectura de interpolaciones de cadenas que usan expresiones de C# más largas, como expresiones switch de coincidencia de patrones o consultas LINQ.

Puede aprender más sobre la característica de nuevas líneas en el artículo Interpolaciones de cadenas de la referencia del lenguaje.

Patrones de lista

Los patrones de lista amplían la coincidencia de patrones para buscar coincidencias con secuencias de elementos de una lista o una matriz. Por ejemplo, sequence is [1, 2, 3] es true cuando sequence es una matriz o una lista de tres enteros (1, 2 y 3). Puede hacer coincidir elementos mediante cualquier patrón, como constante, tipo, propiedad y patrones relacionales. El patrón de descarte (_) coincide con cualquier elemento único y el nuevo patrón de intervalo (..) coincide con cualquier secuencia de cero o más elementos.

Puede encontrar más información sobre los patrones de lista en el artículo sobre coincidencia de patrones en la referencia del lenguaje.

Conversión mejorada de grupo de métodos a delegado

El estándar de C# en conversiones de grupo de métodos ahora incluye el siguiente elemento:

  • La conversión se permite (pero no necesaria) para usar una instancia de delegado existente que ya contiene estas referencias.

Las versiones anteriores del estándar prohibían al compilador reutilizar el objeto delegado creado para una conversión de grupo de métodos. El compilador de C# 11 almacena en caché el objeto delegado creado a partir de una conversión de grupo de métodos y reutiliza ese objeto delegado único. Esta característica se incluyó por primera vez en Visual Studio 2022 versión 17.2 como característica en vista previa y en .NET 7 (versión preliminar 2).

Literales de cadena sin formato

Los literales de cadena sin formato son un nuevo formato para los literales de cadena. Los literales de cadena sin formato pueden contener texto arbitrario, como espacios en blanco, nuevas líneas, comillas insertadas y otros caracteres especiales sin necesidad de secuencias de escape. Un literal de cadena sin formato comienza con al menos tres caracteres de comillas dobles ("""). Y termina con el mismo número de caracteres de comillas dobles. Normalmente, un literal de cadena sin formato usa tres comillas dobles en una sola línea para iniciar la cadena y tres comillas dobles en una línea independiente para finalizar la cadena. Las nuevas líneas que siguen a la comilla de apertura y preceden a la comilla de cierre no se incluyen en el contenido final:

string longMessage = """
    This is a long message.
    It has several lines.
        Some are indented
                more than others.
    Some should start at the first column.
    Some have "quoted text" in them.
    """;

Cualquier espacio en blanco a la izquierda de las comillas dobles de cierre se quitará del literal de cadena. Los literales de cadena sin formato se pueden combinar con la interpolación de cadenas para incluir llaves en el texto de salida. Varios caracteres $ indican cuántas llaves consecutivas comienzan y terminan la interpolación:

var location = $$"""
   You are at {{{Longitude}}, {{Latitude}}}
   """;

En el ejemplo anterior se especifica que dos llaves inician y finalizan una interpolación. La tercera llave de apertura y cierre repetida se incluye en la cadena de salida.

Puede encontrar más información sobre los literales de cadena sin formato en el artículo sobre cadenas de la guía de programación y los artículos de referencia del lenguaje sobre literales de cadena y cadenas interpoladas.

Estructuras predeterminadas automáticas

El compilador de C# 11 garantiza que todos los campos de un tipo struct se inicializarán en su valor predeterminado como parte de la ejecución de un constructor. Este cambio significa que el compilador inicializa automáticamente cualquier campo o propiedad automática no inicializados por un constructor. Las estructuras en las que el constructor no asigna definitivamente todos los campos ahora se compilan, mientras que los campos que no se inicializan explícitamente se establecen en su valor predeterminado. Puede obtener más información sobre cómo afecta este cambio a la inicialización de estructuras en el artículo sobre estructuras.

Span<char> de coincidencia de patrón o ReadOnlySpan<char> en una constante string

Ha podido probar si un elemento string tiene un valor constante específico mediante la coincidencia de patrones en varias versiones. Ahora, puede usar la misma lógica de coincidencia de patrones con variables que son Span<char> o ReadOnlySpan<char>.

Ámbito nameof ampliado

Los nombres de parámetro de tipo y los de parámetro ahora están en el ámbito cuando se usan en una expresión nameof de una declaración de atributo del método. Esta característica significa que puede usar el operador nameof para especificar el nombre de un parámetro de método en un atributo de una declaración de método o parámetro. Esta característica suele ser útil para agregar atributos y llevar a cabo análisis que admitan valores NULL.

Literales de cadena de UTF-8

Puede especificar el sufijo u8 en un literal de cadena para especificar la codificación de caracteres UTF-8. Si la aplicación necesita cadenas UTF-8, para constantes de cadena HTTP o protocolos de texto similares, puede usar esta característica para simplificar la creación de cadenas UTF-8.

Puede obtener más información sobre los literales de cadena UTF-8 en la sección literal de cadena del artículo sobre los tipos de referencia integrados.

Miembros requeridos

Puede agregar el modificadorrequired a propiedades y campos para aplicar constructores y llamadores para inicializar esos valores. El System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute se puede agregar a constructores para informar al compilador de que un constructor inicializa todos los miembros necesarios.

Para obtener más información sobre los miembros necesarios, consulte la sección solo inicial del artículo de propiedades.

Campos ref y variables ref scoped

Puede declarar campos ref en ref struct. Esto admite el uso de tipos como System.Span<T> sin atributos especiales o tipos internos ocultos.

Puede agregar el modificador scoped a cualquier declaración de ref. Esto limita el ámbito al que la referencia puede escapar.

Tipos locales de archivo

A partir de C# 11, el modificador de acceso file se puede usar para crear un tipo cuya visibilidad esté limitada al archivo de origen en el que se declara. Esta característica ayuda a los autores de generadores de código fuente a evitar conflictos de nomenclatura. Puede obtener más información sobre esta característica en el artículo sobre tipos con ámbito de archivo en la sección de referencia del lenguaje.

Vea también