Novedades de C# 13
C# 13 incluye las siguientes características nuevas. Puede probar estas características con la versión más reciente de
- Colecciones de
params
- Nuevo tipo
lock
y semántica. - Nueva secuencia de escape:
\e
. - Mejoras de tipo natural de grupo de métodos
- Acceso implícito al indexador en inicializadores de objetos
- Habilitar variables
ref
locales y contextosunsafe
en iteradores y métodos asincrónicos - Habilitar tipos
ref struct
para implementar interfaces. - Permitir tipos de estructura ref como argumentos para parámetros de tipo en genéricos.
- Ahora se permiten propiedades parciales e indexadores en tipos de
partial
. - La prioridad de resolución de sobrecargas permite a los autores de bibliotecas designar una sobrecarga como superior a las demás.
A partir de Visual Studio 17.12, C# 13 incluye la palabra clave contextual field
como característica de vista previa.
C# 13 es compatible con .NET 9. Para obtener más información, vea Control de versiones del lenguaje C#.
Puede descargar la última versión del SDK de .NET 9 desde la página de descargas de .NET . También puede descargar visual Studio 2022, que incluye el SDK de .NET 9.
Las nuevas características se agregan a la página "Novedades de C#" cuando están disponibles en versiones preliminares públicas. La sección conjunto de trabajo de la página de estado de características de roslyn realiza un seguimiento cuando se combinan las próximas características en la rama principal.
Puede consultar los cambios importantes introducidos en C# 13 en nuestro artículo sobre cambios importantes.
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.
Colecciones de params
El modificador params
no se limita a los tipos de matriz. Ahora puede usar params
con cualquier tipo de colección reconocido, incluidos System.Span<T>, System.ReadOnlySpan<T>y tipos que implementan System.Collections.Generic.IEnumerable<T> y tienen un método Add
. Además de los tipos concretos, también se pueden usar las interfaces System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.ICollection<T>y System.Collections.Generic.IList<T>.
Cuando se usa un tipo de interfaz, el compilador sintetiza el almacenamiento de los argumentos proporcionados. Puede obtener más información en la especificación de funciones para las colecciones params
.
Por ejemplo, las declaraciones de método pueden declarar intervalos como parámetros params
:
public void Concat<T>(params ReadOnlySpan<T> items)
{
for (int i = 0; i < items.Length; i++)
{
Console.Write(items[i]);
Console.Write(" ");
}
Console.WriteLine();
}
Nuevo objeto de bloqueo
El entorno de ejecución de .NET 9 incluye un nuevo tipo para la sincronización de subprocesos, el tipo de System.Threading.Lock. Este tipo proporciona una mejor sincronización de subprocesos a través de su API. El método Lock.EnterScope() entra en un ámbito exclusivo. El ref struct
devuelto que admite el patrón Dispose()
para salir del ámbito exclusivo.
La instrucción lock
de C# reconoce si el destino del bloqueo es un objeto Lock
. Si es así, usa la API actualizada, en lugar de la API tradicional mediante System.Threading.Monitor. El compilador también reconoce si convierte un objeto Lock
a otro tipo y se generaría el código basado en Monitor
. Puede consultar más detalles en la especificación de la funcionalidad del nuevo objeto de bloqueo.
Esta funcionalidad le permite obtener las ventajas del nuevo tipo de biblioteca cambiando el tipo de objeto que lock
. No es necesario cambiar ningún otro código.
Nueva secuencia de escape
Puede usar \e
como una secuencia de escape literal de caracteres para el carácter de ESCAPE
(U+001B
en unicode). Anteriormente, se usaba \u001b
o \x1b
. No se recomienda usar \x1b
porque si los siguientes caracteres siguientes 1b
eran dígitos hexadecimales válidos, esos caracteres se convirtieron en parte de la secuencia de escape.
Tipos naturales de grupo de métodos
Esta característica realiza pequeñas optimizaciones para solucionar sobrecargas con grupos de métodos. Un grupo de métodos consiste en un método y todas las sobrecargas con el mismo nombre. El comportamiento anterior era para que el compilador construya el conjunto completo de métodos candidatos para un grupo de métodos. Si se necesitaba un tipo natural, el tipo natural se determinó a partir del conjunto completo de métodos candidatos.
El nuevo comportamiento consiste en eliminar el conjunto de métodos candidatos en cada ámbito, quitando los métodos candidatos que no son aplicables. Normalmente, los métodos eliminados son métodos genéricos con una aridad incorrecta o cuyos requisitos no se cumplen. El proceso continúa hasta el siguiente ámbito externo solo si no se encuentra ningún método candidato. Este proceso sigue más detenidamente el algoritmo general para la resolución de sobrecargas. Si todos los métodos candidatos encontrados en un ámbito determinado no coinciden, el grupo de métodos no tiene un tipo natural.
Puede leer los detalles de los cambios en la especificación de la propuesta .
Acceso a índices implícitos
El operador de índice implícito "from the end", ^
, ahora se permite en una expresión de inicializador de objeto. Por ejemplo, ahora puede inicializar una matriz en un inicializador de objeto como se muestra en el código siguiente:
public class TimerRemaining
{
public int[] buffer { get; set; } = new int[10];
}
var countdown = new TimerRemaining()
{
buffer =
{
[^1] = 0,
[^2] = 1,
[^3] = 2,
[^4] = 3,
[^5] = 4,
[^6] = 5,
[^7] = 6,
[^8] = 7,
[^9] = 8,
[^10] = 9
}
};
La clase TimerRemaining
incluye una matriz buffer
inicializada a una longitud de 10. En el ejemplo anterior se asignan valores a este array mediante el operador de índice "desde el final" (^
), creando de manera efectiva un array que cuenta de 9 a 0.
En versiones anteriores a C# 13, el operador ^
no se puede usar en un inicializador de objeto. Debe indexar los elementos desde el principio.
ref
y unsafe
en iteradores y métodos de async
Esta característica y las dos características siguientes permiten que los tipos de ref struct
usen nuevas construcciones. No los usará a menos que escriba sus propios tipos ref struct
. Lo más probable es que veas una ventaja indirecta ya que System.Span<T> y System.ReadOnlySpan<T> obtengan más funcionalidad.
Antes de C# 13, los métodos de iterador (métodos que usan yield return
) y async
métodos no podían declarar variables ref
locales ni podían tener un contexto de unsafe
.
En C# 13, los métodos async
pueden declarar variables locales ref
o variables locales de tipo ref struct
. Sin embargo, no se puede acceder a esas variables a través de un límite de await
. Tampoco se puede acceder a estos a través de un límite de yield return
.
Esta relajación de la restricción permite al compilador admitir el uso seguro comprobable de variables locales ref
y tipos de ref struct
en más contextos. Puede usar de forma segura tipos como System.ReadOnlySpan<T> en estos métodos. El compilador le indica si infringe las reglas de seguridad.
De la misma manera, C# 13 permite contextos unsafe
en métodos iteradores. Sin embargo, todas las declaraciones yield return
y yield break
deben estar en contextos seguros.
allows ref struct
Antes de C# 13, los tipos de ref struct
no se podían declarar como argumento de tipo para un tipo o método genéricos. Ahora, las declaraciones de tipos genéricos pueden agregar una antirestricción, allows ref struct
. Esta anti-restricción declara que el argumento de tipo proporcionado para ese parámetro de tipo puede ser de tipo ref struct
. El compilador aplica reglas de seguridad de referencia en todas las instancias de ese parámetro de tipo.
Por ejemplo, puede declarar un tipo genérico como el código siguiente:
public class C<T> where T : allows ref struct
{
// Use T as a ref struct:
public void M(scoped T p)
{
// The parameter p must follow ref safety rules
}
}
Esto permite usar tipos como System.Span<T> y System.ReadOnlySpan<T> con algoritmos genéricos, si procede. Puede obtener más información en las actualizaciones para where
y en el artículo de la guía de programación sobre restricciones genéricas .
Interfaces ref struct
Antes de C# 13, los tipos de ref struct
no podían implementar interfaces. A partir de C# 13, sí pueden. Puede declarar que el tipo ref struct
implementa una interfaz. Sin embargo, para garantizar las reglas de seguridad de ref, no se puede convertir un tipo ref struct
en un tipo de interfaz. Esa conversión es una conversión de clase boxing y podría vulnerar la seguridad de ref. Desde esa regla, los tipos de ref struct
no pueden declarar métodos que implementen explícitamente un método de interfaz. Además, los tipos de ref struct
deben implementar todos los métodos declarados en una interfaz, incluidos esos métodos con una implementación predeterminada.
Obtenga más información en las actualizaciones sobre los tipos ref struct
.
Más miembros parciales
Puede declarar propiedades partial
e indizadores partial
en C# 13. Las propiedades parciales y los indexadores suelen seguir las mismas reglas que los métodos partial
: se crea una declaración declaratoria y una declaración de implementación. Las firmas de las dos declaraciones deben coincidir. No obstante, hay una restricción: se puede usar una declaración de propiedad automática para implementar una propiedad parcial. A las propiedades que no declaran un cuerpo se las considera la declaración declaratoria.
public partial class C
{
// Declaring declaration
public partial string Name { get; set; }
}
public partial class C
{
// implementation declaration:
private string _name;
public partial string Name
{
get => _name;
set => _name = value;
}
}
Puede obtener más información en el artículo sobre miembros parciales.
Prioridad de resolución de sobrecarga
En C# 13, el compilador reconoce el OverloadResolutionPriorityAttribute para preferir una sobrecarga sobre otra. Los autores de bibliotecas pueden usar este atributo para asegurarse de que se prefiere una sobrecarga nueva y mejor sobre una sobrecarga existente. Por ejemplo, puede agregar una nueva sobrecarga con mejor rendimiento. No desea interrumpir el código existente que usa la biblioteca, pero quiere que los usuarios actualicen a la nueva versión cuando se vuelvan a compilar. Puede usar Prioridad de resolución de sobrecarga para informar al compilador sobre qué sobrecarga es prioritaria. Se prefieren las sobrecargas con la prioridad más alta.
Esta característica está pensada para que los autores de bibliotecas eviten ambigüedad al agregar nuevas sobrecargas. Los autores de bibliotecas deben usar cuidado con este atributo para evitar confusiones.
Palabra clave field
La palabra clave contextual field
está en C# 13 como característica de vista previa. El token field
accede al campo auxiliar sintetizado por el compilador en un descriptor de acceso de propiedad. Permite escribir un cuerpo del descriptor de acceso sin declarar un campo auxiliar explícito en la declaración del tipo. Puede declarar un cuerpo para uno o ambos descriptores de acceso en una propiedad auxiliar de campo.
La característica field
se publica como una característica en versión preliminar. Queremos aprender de sus experiencias con ella. Es posible que hay cambio importante o se produzca cierta confusión al leer el código en tipos que también incluyen un campo llamado field
. Puede usar @field
o this.field
para desambiguar entre la palabra clave field
y el identificador.
Importante
La palabra clave field
es una característica en versión preliminar de C# 13. Debe usar .NET 9 y establecer el elemento <LangVersion>
en preview
en el archivo de proyecto para poder usar la palabra clave contextual field
.
Debe tener cuidado con el uso de la característica de palabra clave field
en una clase que tenga un campo denominado field
. La nueva palabra clave field
sombrea un campo denominado field
en el ámbito de un descriptor de acceso de propiedad. Puede cambiar el nombre de la variable field
o usar el token de @
para hacer referencia al identificador de field
como @field
. Para obtener más información, consulte la especificación de la función de la palabra clave field
.
Si prueba esta funcionalidad y tiene algo que comentar, inclúyalos en la incidencia sobre la funcionalidad en el repositorio csharplang
.