Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
C# 15 incluye las siguientes características nuevas. Pruebe estas características mediante la versión más reciente de Visual Studio 2026 insiders o el SDK de versión preliminar de .NET 11:
C# 15 es la versión preliminar más reciente de C#. Las versiones preliminares de .NET 11 admiten C# 15. Para obtener más información, vea Control de versiones del lenguaje C#.
Puede descargar el SDK de versión preliminar de .NET 11 más reciente desde la página de descargas de .NET. También puede descargar visual Studio 2026 insiders, que incluye el SDK de versión preliminar de .NET 11.
La página "Novedades de C#" agrega nuevas características 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 encontrar los cambios importantes introducidos en C# 15 en nuestro artículo sobre los 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.
Argumentos de expresiones de colección
Puede pasar argumentos al constructor o al método factory de la colección subyacente mediante un with(...) elemento como primer elemento de una expresión de colección. Esta característica permite especificar capacidad, comparadores u otros parámetros de constructor directamente dentro de la sintaxis de la expresión de colección.
En el ejemplo siguiente se muestra cómo pasar un argumento de capacidad a un List<T> constructor y un comparador a :HashSet<T>
string[] values = ["one", "two", "three"];
// Pass capacity argument to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];
// Pass comparer argument to HashSet<T> constructor
HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
// set contains only one element because all strings are equal with OrdinalIgnoreCase
Para más información sobre los argumentos de expresiones de colección, consulte el artículo de referencia del lenguaje sobre expresiones de colección o la especificación de características. Para obtener información sobre el uso de argumentos de expresión de colección en inicializadores de colección, vea Inicializadores de objeto y colección.
Tipos de unión
C# 15 presenta tipos de unión, que representan un valor que puede ser uno de varios tipos de casos. Declare una unión utilizando la palabra clave union:
public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);
public union Pet(Cat, Dog, Bird);
Las uniones proporcionan conversiones implícitas de cada tipo de caso y el compilador garantiza que switch las expresiones son exhaustivas en todos los tipos de casos:
Pet pet = new Dog("Rex");
string name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
El runtime incluye los tipos UnionAttribute y IUnion a partir de .NET 11 Preview 5. Algunas características de la especificación de propuesta aún no se han implementado. Estas características vienen en futuras versiones preliminares.
Para obtener más información, consulte Tipos de unión en la referencia del lenguaje o la especificación de características.
Jerarquías cerradas
A partir de C# 15, puede aplicar el closed modificador a una clase para declarar una jerarquía cerrada. Una clase cerrada solo se puede derivar de dentro de su ensamblado declarativo, que corrige el conjunto de descendientes directos en tiempo de compilación:
public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;
Dado que el compilador conoce todos los descendientes directos, una switch expresión que controla cada una de ellas es exhaustiva y no necesita un brazo predeterminado:
string Describe(GateState state) => state switch
{
Closed => "closed",
Open(var percent) => $"{percent}% open",
// No warning: every direct descendant of 'GateState' is handled.
};
El closed modificador es una palabra clave contextual. Una closed clase está implícitamente abstract y no se puede combinar con sealed, statico un modificador explícito abstract . La derivación no es transitiva: un descendiente no cerrado de una clase cerrada puede aun así servir como base para la derivación en otros ensamblados. Para ampliar la comprobación exhaustiva de la jerarquía, marque también descendientes intermedios closed.
Nota:
En la versión preliminar 5 de C# 15, el entorno de ejecución aún no envía System.Runtime.CompilerServices.ClosedAttribute. Hasta que lo haga, todos los proyectos que usen el closed modificador deben declarar el propio atributo:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ClosedAttribute : Attribute { }
Para obtener más información, consulte el modificador closed y los patrones de jerarquía Closed en la referencia del lenguaje, o la especificación de la característica. Puede copiar los ejemplos de esta sección, incluida la solución alternativa ClosedAttribute, del proyecto de snippets palabras clave en el repositorio de GitHub dotnet/docs.
Seguridad de memoria
C# 15 comienza un esfuerzo de versión múltiple para redefinir la seguridad de la memoria en el lenguaje. El objetivo es vincular el unsafe contexto a las operaciones que realmente acceden a la memoria no administrada, en lugar de a la existencia de tipos de puntero. La mayoría de las vulnerabilidades de seguridad de memoria proceden de estas operaciones de acceso, por lo que el lenguaje hace que destaquen para los revisores y auditores.
En el modelo completo, unsafe aplicado a un miembro lo marca como requires-unsafe: la obligación de auditoría recae en quien realiza la llamada, que debe usar el miembro en un contexto unsafe. Un ensamblaje acepta esta imposición, y el compilador registra esta decisión con el atributo System.Runtime.CompilerServices.MemorySafetyRulesAttribute. El modelo también añade una safe palabra clave contextual que marca extern los miembros y los campos con diseño explícito como seguros. Juntas, estas reglas hacen que los límites de la posible falta de seguridad de memoria sean explícitos en un programa.
El primer paso incluye las relajaciones del puntero. Al compilar con la versión del preview lenguaje, las siguientes operaciones ya no requieren un unsafe contexto:
- Declarar un tipo de puntero y tomar la dirección de una variable con el
&operador . - La instrucción
fixed, que fija una variable. - Convertir una
stackallocexpresión en un puntero. - El operador
sizeofse aplica a cualquier tipo no administrado.
En el ejemplo siguiente se crea y ancla un puntero sin contexto unsafe :
int number = 42;
int* pointer = &number;
int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
// Dereferencing the pointer still requires an unsafe context.
}
Las operaciones que acceden a la memoria a la que se apunta, como la indirección de puntero (*p), el acceso a miembros de puntero (p->member), el acceso a elementos de puntero (p[i]) y la invocación de punteros a función, siguen requiriendo un contexto unsafe.
El modelo de miembros requires-unsafe, la adhesión del ensamblado a las reglas actualizadas de seguridad de memoria y la palabra clave contextual safe llegan en una versión preliminar posterior.
Para obtener más información, consulte Código no seguro, tipos de puntero y punteros de función en la referencia del lenguaje o la especificación de características.