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.
Nota
Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.
Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.
Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .
Problema del campeón: https://github.com/dotnet/csharplang/issues/3297
Resumen
Permitir anotaciones que aceptan valores NULL para parámetros de tipo que no están restringidos a tipos de valor o tipos de referencia: T?
.
static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }
Anotación ?
En C#8, las anotaciones de ?
solo se podían aplicar a parámetros de tipo restringidos explícitamente a tipos de valor o tipos de referencia.
En C#9, las anotaciones ?
se pueden aplicar a cualquier parámetro de tipo, independientemente de las restricciones.
A menos que un parámetro de tipo se restrinja explícitamente a los tipos de valor, las anotaciones solo se pueden aplicar dentro de un contexto de #nullable enable
.
Si un parámetro de tipo T
se sustituye por un tipo de referencia, entonces T?
representa una instancia anulable de ese tipo de referencia.
var s1 = new string[0].FirstOrDefault(); // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2
Si T
se sustituye por un tipo de valor, T?
representa una instancia de T
.
var i1 = new int[0].FirstOrDefault(); // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2
Si T
se sustituye por un tipo anotado U?
, T?
representa el tipo anotado U?
en lugar de U??
.
var u1 = new U[0].FirstOrDefault(); // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2
Si T
se sustituye por un tipo U
, T?
representa U?
, incluso dentro de un contexto de #nullable disable
.
#nullable disable
var u3 = new U[0].FirstOrDefault(); // U? u3
Para los valores devueltos, T?
equivale a [MaybeNull]T
; para los valores de argumento, T?
es equivalente a [AllowNull]T
.
La equivalencia es importante al invalidar o implementar interfaces de un ensamblado compilado con C#8.
public abstract class A
{
[return: MaybeNull] public abstract T F1<T>();
public abstract void F2<T>([AllowNull] T t);
}
public class B : A
{
public override T? F1<T>() where T : default { ... } // matches A.F1<T>()
public override void F2<T>(T? t) where T : default { ... } // matches A.F2<T>()
}
default
restricción
Para la compatibilidad con el código existente en el que los métodos genéricos invalidados y implementados explícitamente no podían incluir cláusulas de restricción explícitas, T?
en un método invalidado o implementado explícitamente se trata como Nullable<T>
donde T
es un tipo de valor.
Para permitir anotaciones para parámetros de tipo restringidos a tipos de referencia, C#8 permitió restricciones explícitas de where T : class
y where T : struct
en el método invalidado o implementado explícitamente.
class A1
{
public virtual void F1<T>(T? t) where T : struct { }
public virtual void F1<T>(T? t) where T : class { }
}
class B1 : A1
{
public override void F1<T>(T? t) /*where T : struct*/ { }
public override void F1<T>(T? t) where T : class { }
}
Para permitir anotaciones para parámetros de tipo que no están restringidos a tipos de referencia o tipos de valor, C#9 permite una nueva restricción de where T : default
.
class A2
{
public virtual void F2<T>(T? t) where T : struct { }
public virtual void F2<T>(T? t) { }
}
class B2 : A2
{
public override void F2<T>(T? t) /*where T : struct*/ { }
public override void F2<T>(T? t) where T : default { }
}
Es un error usar una restricción default
que no sea en una invalidación de método o implementación explícita.
Es un error usar una restricción default
cuando el parámetro de tipo correspondiente en el método de interfaz o invalidado está restringido a un tipo de referencia o tipo de valor.
Reuniones de diseño
C# feature specifications