Especificación de tipos de referencia que aceptan valores NULLNullable Reference Types Specification
Se trata de un trabajo en curso; faltan varias partes o están incompletas.This is a work in progress - several parts are missing or incomplete.
Esta característica agrega dos nuevos tipos de tipos que aceptan valores NULL (tipos de referencia que aceptan valores NULL y tipos genéricos que aceptan valores NULL) a los tipos de valor que aceptan valores NULL existentes y presenta un análisis de flujo estático con fines de seguridad nula.This feature adds two new kinds of nullable types (nullable reference types and nullable generic types) to the existing nullable value types, and introduces a static flow analysis for purpose of null-safety.
SintaxisSyntax
Tipos de referencia que aceptan valores NULL y parámetros de tipo que aceptan valores NULLNullable reference types and nullable type parameters
Los tipos de referencia que aceptan valores NULL y los parámetros de tipo que aceptan valores NULL tienen la misma sintaxis T? que la forma abreviada de tipos de valor que aceptan valores NULL, pero no tienen una forma larga correspondiente.Nullable reference types and nullable type parameters have the same syntax T? as the short form of nullable value types, but do not have a corresponding long form.
Para los fines de la especificación, nullable_type se cambia el nombre de la producción actual a y nullable_value_type nullable_reference_type nullable_type_parameter se agregan las producciones:For the purposes of the specification, the current nullable_type production is renamed to nullable_value_type, and nullable_reference_type and nullable_type_parameter productions are added:
type
: value_type
| reference_type
| nullable_type_parameter
| type_parameter
| type_unsafe
;
reference_type
: ...
| nullable_reference_type
;
nullable_reference_type
: non_nullable_reference_type '?'
;
non_nullable_reference_type
: reference_type
;
nullable_type_parameter
: non_nullable_non_value_type_parameter '?'
;
non_nullable_non_value_type_parameter
: type_parameter
;
non_nullable_reference_typeEn nullable_reference_type , debe ser un tipo de referencia que no acepte valores NULL (clase, interfaz, delegado o matriz).The non_nullable_reference_type in a nullable_reference_type must be a nonnullable reference type (class, interface, delegate or array).
non_nullable_non_value_type_parameterEn nullable_type_parameter debe ser un parámetro de tipo que no esté restringido para ser un tipo de valor.The non_nullable_non_value_type_parameter in nullable_type_parameter must be a type parameter that isn't constrained to be a value type.
Los tipos de referencia que aceptan valores NULL y los parámetros de tipo que aceptan valores NULL no pueden aparecer en las siguientes posiciones:Nullable reference types and nullable type parameters cannot occur in the following positions:
- como una clase base o una interfazas a base class or interface
- como receptor de un
member_accessas the receiver of amember_access - como
typeen unobject_creation_expressionas thetypein anobject_creation_expression - como
delegate_typeen undelegate_creation_expressionas thedelegate_typein adelegate_creation_expression - como
typeenis_expression,catch_clauseotype_patternas thetypein anis_expression, acatch_clauseor atype_pattern - como
interfaceen un nombre completo de miembro de interfazas theinterfacein a fully qualified interface member name
Se proporciona una advertencia en nullable_reference_type y nullable_type_parameter en un contexto de anotación que acepta valores NULL deshabilitado .A warning is given on a nullable_reference_type and nullable_type_parameter in a disabled nullable annotation context.
class``class?restricción andclass and class? constraint
La class restricción tiene un homólogo que acepta valores NULL class? :The class constraint has a nullable counterpart class?:
primary_constraint
: ...
| 'class' '?'
;
Se debe crear una instancia de un parámetro de tipo restringido con class (en un contexto de anotación habilitado ) con un tipo de referencia que no acepte valores NULL.A type parameter constrained with class (in an enabled annotation context) must be instantiated with a nonnullable reference type.
Se puede crear una instancia de un parámetro de tipo restringido con class? (o class en un contexto de anotación deshabilitado ) con un tipo de referencia que acepte valores NULL o que no acepte valores NULL.A type parameter constrained with class? (or class in a disabled annotation context) may either be instantiated with a nullable or nonnullable reference type.
Se proporciona una advertencia en una class? restricción en un contexto de anotación deshabilitado .A warning is given on a class? constraint in a disabled annotation context.
notnull restricciónnotnull constraint
Un parámetro de tipo restringido con notnull no puede ser un tipo que acepta valores NULL (tipo de valor que acepta valores NULL, tipo de referencia que acepta valores NULL o parámetro de tipo que acepta valores NULL).A type parameter constrained with notnull may not be a nullable type (nullable value type, nullable reference type or nullable type parameter).
primary_constraint
: ...
| 'notnull'
;
default restriccióndefault constraint
La default restricción se puede usar en una invalidación de método o en una implementación explícita para eliminar la ambigüedad que T? significa "parámetro de tipo que acepta valores NULL" de "tipo de valor que acepta valores NULL" ( Nullable<T> ).The default constraint can be used on a method override or explicit implementation to disambiguate T? meaning "nullable type parameter" from "nullable value type" (Nullable<T>). Si falta la default restricción T? , una sintaxis en una implementación de invalidación o explícita se interpretará como Nullable<T>Lacking the default constraint a T? syntax in an override or explicit implementation will be interpreted as Nullable<T>
Consulta https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/unconstrained-type-parameter-annotations.md#default-constraint.See https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/unconstrained-type-parameter-annotations.md#default-constraint
El operador null-permisivoThe null-forgiving operator
El operador posterior a la corrección ! se denomina operador permisivo nulo.The post-fix ! operator is called the null-forgiving operator. Se puede aplicar en un primary_expression o en un null_conditional_expression:It can be applied on a primary_expression or within a null_conditional_expression:
primary_expression
: ...
| null_forgiving_expression
;
null_forgiving_expression
: primary_expression '!'
;
null_conditional_expression
: primary_expression null_conditional_operations_no_suppression suppression?
;
null_conditional_operations_no_suppression
: null_conditional_operations? '?' '.' identifier type_argument_list?
| null_conditional_operations? '?' '[' argument_list ']'
| null_conditional_operations '.' identifier type_argument_list?
| null_conditional_operations '[' argument_list ']'
| null_conditional_operations '(' argument_list? ')'
;
null_conditional_operations
: null_conditional_operations_no_suppression suppression?
;
suppression
: '!'
;
Por ejemplo:For example:
var v = expr!;
expr!.M();
_ = a?.b!.c;
primary_expressionY null_conditional_operations_no_suppression deben ser de un tipo que acepte valores NULL.The primary_expression and null_conditional_operations_no_suppression must be of a nullable type.
El operador postfijo ! no tiene ningún efecto en tiempo de ejecución, sino que se evalúa como el resultado de la expresión subyacente.The postfix ! operator has no runtime effect - it evaluates to the result of the underlying expression. Su único rol es cambiar el estado null de la expresión a "not null" y limitar las advertencias que se dan en su uso.Its only role is to change the null state of the expression to "not null", and to limit warnings given on its use.
Directivas de compilador que aceptan valores NULLNullable compiler directives
#nullable las directivas controlan la anotación y los contextos de advertencia que aceptan valores NULL.#nullable directives control the nullable annotation and warning contexts.
pp_directive
: ...
| pp_nullable
;
pp_nullable
: whitespace? '#' whitespace? 'nullable' whitespace nullable_action (whitespace nullable_target)? pp_new_line
;
nullable_action
: 'disable'
| 'enable'
| 'restore'
;
nullable_target
: 'warnings'
| 'annotations'
;
#pragma warning las directivas se expanden para permitir cambiar el contexto de advertencia que acepta valores NULL:#pragma warning directives are expanded to allow changing the nullable warning context:
pragma_warning_body
: ...
| 'warning' whitespace warning_action whitespace 'nullable'
;
Por ejemplo:For example:
#pragma warning disable nullable
Contextos que aceptan valores NULLNullable contexts
Cada línea de código fuente tiene un contexto de anotación que acepta valores NULL y un contexto de advertencia que acepta valores NULL.Every line of source code has a nullable annotation context and a nullable warning context. Estos controlan si las anotaciones que aceptan valores NULL tienen efecto y si se proporcionan advertencias de nulabilidad.These control whether nullable annotations have effect, and whether nullability warnings are given. El contexto de anotación de una línea determinada está deshabilitado o habilitado.The annotation context of a given line is either disabled or enabled. El contexto de advertencia de una línea determinada está deshabilitado o habilitado.The warning context of a given line is either disabled or enabled.
Ambos contextos se pueden especificar en el nivel de proyecto (fuera del código fuente de C#) o en cualquier lugar dentro de un archivo de código fuente mediante #nullable directivas de preprocesador.Both contexts can be specified at the project level (outside of C# source code), or anywhere within a source file via #nullable pre-processor directives. Si no se proporciona ninguna configuración de nivel de proyecto, el valor predeterminado es que ambos contextos estén deshabilitados.If no project level settings are provided the default is for both contexts to be disabled.
La #nullable directiva controla la anotación y los contextos de advertencia en el texto de origen y tiene prioridad sobre la configuración de nivel de proyecto.The #nullable directive controls the annotation and warning contexts within the source text, and take precedence over the project-level settings.
Una Directiva establece los contextos que controla para las siguientes líneas de código, hasta que otra directiva la invalida o hasta el final del archivo de código fuente.A directive sets the context(s) it controls for subsequent lines of code, until another directive overrides it, or until the end of the source file.
El efecto de las directivas es el siguiente:The effect of the directives is as follows:
#nullable disable: Establece la anotación y los contextos de advertencia que aceptan valores NULL en deshabilitado .#nullable disable: Sets the nullable annotation and warning contexts to disabled#nullable enable: Establece la anotación y los contextos de advertencia que aceptan valores NULL en habilitado .#nullable enable: Sets the nullable annotation and warning contexts to enabled#nullable restore: Restaura los contextos de advertencia y anotación que aceptan valores NULL a la configuración del proyecto.#nullable restore: Restores the nullable annotation and warning contexts to project settings#nullable disable annotations: Establece el contexto de anotación que acepta valores NULL en deshabilitado .#nullable disable annotations: Sets the nullable annotation context to disabled#nullable enable annotations: Establece el contexto de anotación que acepta valores NULL en habilitado#nullable enable annotations: Sets the nullable annotation context to enabled#nullable restore annotations: Restaura el contexto de anotación que acepta valores NULL a la configuración del proyecto.#nullable restore annotations: Restores the nullable annotation context to project settings#nullable disable warnings: Establece el contexto de advertencia que acepta valores NULL en deshabilitado .#nullable disable warnings: Sets the nullable warning context to disabled#nullable enable warnings: Establece el contexto de advertencia que acepta valores NULL en habilitado#nullable enable warnings: Sets the nullable warning context to enabled#nullable restore warnings: Restaura el contexto de advertencia que acepta valores NULL a la configuración del proyecto.#nullable restore warnings: Restores the nullable warning context to project settings
Nulabilidad de tiposNullability of types
Un tipo determinado puede tener uno de tres nullabilities: desconocen, nonnullable y Nullable.A given type can have one of three nullabilities: oblivious, nonnullable, and nullable.
Los tipos que no aceptan valores NULL pueden producir advertencias si null se le asigna un valor potencial.Nonnullable types may cause warnings if a potential null value is assigned to them. Sin embargo, los tipos desconocen y que aceptan valores NULL son "asignable null" y pueden tener null valores asignados sin advertencias.Oblivious and nullable types, however, are "null-assignable" and can have null values assigned to them without warnings.
Los valores de desconocen y los tipos que no aceptan valores NULL se pueden desreferenciar o asignar sin advertencias.Values of oblivious and nonnullable types can be dereferenced or assigned without warnings. Sin embargo, los valores de los tipos que aceptan valores NULL son "produjeron valores NULL" y pueden provocar advertencias al desreferenciarse o asignarse sin una comprobación nula adecuada.Values of nullable types, however, are "null-yielding" and may cause warnings when dereferenced or assigned without proper null checking.
El estado predeterminado NULL de un tipo de rendimiento nulo es "quizás null" o "quizás default".The default null state of a null-yielding type is "maybe null" or "maybe default". El estado Null predeterminado de un tipo de rendimiento que no es NULL es "not null".The default null state of a non-null-yielding type is "not null".
El tipo de tipo y el contexto de anotación que acepta valores NULL que tiene lugar en determina su nulabilidad:The kind of type and the nullable annotation context it occurs in determine its nullability:
- Un tipo de valor que no acepta valores NULL
Ssiempre es no acepta valores NULLA nonnullable value typeSis always nonnullable - Un tipo de valor que acepta valores NULL
S?siempre admite valores NULLA nullable value typeS?is always nullable - Un tipo de referencia sin anotar
Cen un contexto de anotación deshabilitado es desconocenAn unannotated reference typeCin a disabled annotation context is oblivious - Un tipo de referencia sin anotar
Cen un contexto de anotación habilitado no admite valores NULLAn unannotated reference typeCin an enabled annotation context is nonnullable - Un tipo de referencia que acepta valores NULL admite
C?valores NULL (pero se puede producir una advertencia en un contexto de anotación deshabilitado )A nullable reference typeC?is nullable (but a warning may be yielded in a disabled annotation context)
Los parámetros de tipo también tienen en cuenta las restricciones:Type parameters additionally take their constraints into account:
- Parámetro de tipo
Ten el que todas las restricciones (si existen) son tipos que aceptan valores NULL o laclass?restricción admite valores NULL .A type parameterTwhere all constraints (if any) are either nullable types or theclass?constraint is nullable - Un parámetro de tipo en
Tel que al menos una restricción es desconocen o que no admite valores NULL , o una de lasstructclassrestricciones onotnulles.A type parameterTwhere at least one constraint is either oblivious or nonnullable or one of thestructorclassornotnullconstraints is- desconocen en un contexto de anotación deshabilitadooblivious in a disabled annotation context
- no acepta valores NULL en un contexto de anotación habilitadononnullable in an enabled annotation context
- Un parámetro de tipo que acepta valores NULL admite
T?valores NULL, pero se produce una advertencia en un contexto de anotación deshabilitado siTno es un tipo de valorA nullable type parameterT?is nullable, but a warning is yielded in a disabled annotation context ifTisn't a value type
Desconocen frente a no NullableOblivious vs nonnullable
typeSe considera que se produce en un contexto de anotación determinado cuando el último token del tipo está dentro de ese contexto.A type is deemed to occur in a given annotation context when the last token of the type is within that context.
Si un tipo de referencia determinado C en el código fuente se interpreta como desconocen o no acepta valores NULL, depende del contexto de la anotación de ese código fuente.Whether a given reference type C in source code is interpreted as oblivious or nonnullable depends on the annotation context of that source code. Pero una vez establecido, se considera parte de ese tipo y "viaja con él", por ejemplo, durante la sustitución de los argumentos de tipo genérico.But once established, it is considered part of that type, and "travels with it" e.g. during substitution of generic type arguments. Es como si hubiera una anotación como ? en el tipo, pero no es visible.It is as if there is an annotation like ? on the type, but invisible.
RestriccionesConstraints
Los tipos de referencia que aceptan valores NULL se pueden usar como restricciones genéricas.Nullable reference types can be used as generic constraints.
class? es una nueva restricción que denota "posible tipo de referencia que acepta valores NULL", mientras que class en un contexto de anotación habilitado denota "tipo de referencia que no acepta valores NULL".class? is a new constraint denoting "possibly nullable reference type", whereas class in an enabled annotation context denotes "nonnullable reference type".
default es una nueva restricción que denota un parámetro de tipo que no se sabe que es un tipo de referencia o de valor.default is a new constraint denoting a type parameter that isn't known to be a reference or value type. Solo se puede usar en métodos invalidados y implementados explícitamente.It can only be used on overridden and explicitly implemented methods. Con esta restricción, T? significa un parámetro de tipo que acepta valores NULL, en lugar de ser un método abreviado para Nullable<T> .With this constraint, T? means a nullable type parameter, as opposed to being a shorthand for Nullable<T>.
notnull es una nueva restricción que denota un parámetro de tipo que no acepta valores NULL.notnull is a new constraint denoting a type parameter that is nonnullable.
La nulabilidad de un argumento de tipo o de una restricción no afecta a si el tipo satisface la restricción, excepto en el caso de que ya sea el caso hoy (los tipos de valor que aceptan valores NULL no satisfacen la struct restricción).The nullability of a type argument or of a constraint does not impact whether the type satisfies the constraint, except where that is already the case today (nullable value types do not satisfy the struct constraint). Sin embargo, si el argumento de tipo no satisface los requisitos de nulabilidad de la restricción, se puede proporcionar una advertencia.However, if the type argument does not satisfy the nullability requirements of the constraint, a warning may be given.
Estado NULL y seguimiento nuloNull state and null tracking
Cada expresión de una ubicación de origen determinada tiene un Estado null, que indica si se considera que puede evaluarse como null.Every expression in a given source location has a null state, which indicated whether it is believed to potentially evaluate to null. El estado nulo es "no NULL", "quizás null" o "quizás default".The null state is either "not null", "maybe null", or "maybe default". El estado NULL se usa para determinar si se debe proporcionar una advertencia sobre las conversiones y desreferenciaciones no seguras de NULL.The null state is used to determine whether a warning should be given about null-unsafe conversions and dereferences.
La distinción entre "quizás null" y "quizás default" es sutil y se aplica a los parámetros de tipo.The distinction between "maybe null" and "maybe default" is subtle and applies to type parameters. La distinción es que un parámetro de tipo T que tiene el estado "quizás null" significa que el valor está en el dominio de valores válidos para, T sin embargo, ese valor legal puede incluir null .The distinction is that a type parameter T which has the state "maybe null" means the value is in the domain of legal values for T however that legal value may include null. En los casos en los que el valor predeterminado es "quizás default", el valor puede estar fuera del dominio legal de los valores de T .Where as a "maybe default" means that the value may be outside the legal domain of values for T.
Ejemplo:Example:
// The value `t` here has the state "maybe null". It's possible for `T` to be instantiated
// with `string?` in which case `null` would be within the domain of legal values here. The
// assumption though is the value provided here is within the legal values of `T`. Hence
// if `T` is `string` then `null` will not be a value, just as we assume that `null` is not
// provided for a normal `string` parameter
void M<T>(T t)
{
// There is no guarantee that default(T) is within the legal values for T hence the
// state *must* be "maybe-default" and hence `local` must be `T?`
T? local = default(T);
}
Seguimiento de valores NULL para variablesNull tracking for variables
En el caso de ciertas expresiones que indican variables, campos o propiedades, se realiza un seguimiento del estado Null entre las repeticiones, en función de las asignaciones a ellos, las pruebas realizadas en ellos y el flujo de control entre ellos.For certain expressions denoting variables, fields or properties, the null state is tracked between occurrences, based on assignments to them, tests performed on them and the control flow between them. Esto es similar a la forma en que se realiza el seguimiento de la asignación definitiva para las variables.This is similar to how definite assignment is tracked for variables. Las expresiones de las que se ha realizado un seguimiento son las siguientes:The tracked expressions are the ones of the following form:
tracked_expression
: simple_name
| this
| base
| tracked_expression '.' identifier
;
Donde los identificadores denotan campos o propiedades.Where the identifiers denote fields or properties.
El estado null de las variables a las que se hace seguimiento es "not null" en código inaccesible.The null state for tracked variables is "not null" in unreachable code. Esto sigue otras decisiones relacionadas con el código inaccesible como la consideración de la asignación definitiva de todas las variables locales.This follows other decisions around unreachable code like considering all locals to be definitely assigned.
Describir las transiciones de estado Null similares a las asignaciones definitivasDescribe null state transitions similar to definite assignment
Estado null para expresionesNull state for expressions
El estado null de una expresión se deriva de su forma y tipo, y del estado null de las variables implicadas en él.The null state of an expression is derived from its form and type, and from the null state of variables involved in it.
LiteralesLiterals
El estado null de un null literal depende del tipo de destino de la expresión.The null state of a null literal depends on the target type of the expression. Si el tipo de destino es un parámetro de tipo restringido a un tipo de referencia, es "quizás default".If the target type is a type parameter constrained to a reference type then it's "maybe default". En caso contrario, es "quizás null".Otherwise it is "maybe null".
El estado null de un default literal depende del tipo de destino del default literal.The null state of a default literal depends on the target type of the default literal. Un default literal con el tipo de destino T tiene el mismo estado null que la default(T) expresión.A default literal with target type T has the same null state as the default(T) expression.
El estado null de cualquier otro literal es "not null".The null state of any other literal is "not null".
Nombres simplesSimple names
Si un simple_name no se clasifica como un valor, su estado NULL es "not null".If a simple_name is not classified as a value, its null state is "not null". En caso contrario, se trata de una expresión de la que se realiza un seguimiento y su estado NULL es el estado NULL del que se realiza el seguimiento en esta ubicación de origen.Otherwise it is a tracked expression, and its null state is its tracked null state at this source location.
Acceso a miembrosMember access
Si un member_access no se clasifica como un valor, su estado NULL es "not null".If a member_access is not classified as a value, its null state is "not null". De lo contrario, si se trata de una expresión de la que se realiza un seguimiento, su estado NULL es el estado NULL del que se realiza el seguimiento en esta ubicación de origen.Otherwise, if it is a tracked expression, its null state is its tracked null state at this source location. De lo contrario, su estado NULL es el estado Null predeterminado de su tipo.Otherwise its null state is the default null state of its type.
var person = new Person();
// The receiver is a tracked expression hence the member_access of the property
// is tracked as well
if (person.FirstName is not null)
{
Use(person.FirstName);
}
// The return of an invocation is not a tracked expression hence the member_access
// of the return is also not tracked
if (GetAnonymous().FirstName is not null)
{
// Warning: Cannot convert null literal to non-nullable reference type.
Use(GetAnonymous().FirstName);
}
void Use(string s)
{
// ...
}
public class Person
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
private static Person s_anonymous = new Person();
public static Person GetAnonymous() => s_anonymous;
}
Expresiones de invocaciónInvocation expressions
Si invocation_expression invoca un miembro declarado con uno o varios atributos para un comportamiento especial nulo, el estado NULL se determina mediante esos atributos.If an invocation_expression invokes a member that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. De lo contrario, el estado null de la expresión es el estado Null predeterminado de su tipo.Otherwise the null state of the expression is the default null state of its type.
invocation_expressionEl compilador no realiza el seguimiento del estado null de un.The null state of an invocation_expression is not tracked by the compiler.
// The result of an invocation_expression is not tracked
if (GetText() is not null)
{
// Warning: Converting null literal or possible null value to non-nullable type.
string s = GetText();
// Warning: Dereference of a possibly null reference.
Use(s);
}
// Nullable friendly pattern
if (GetText() is string s)
{
Use(s);
}
string? GetText() => ...
Use(string s) { }
Acceso a elementosElement access
Si element_access invoca un indexador que se declara con uno o más atributos para un comportamiento especial nulo, los atributos determinan el estado null.If an element_access invokes an indexer that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. De lo contrario, el estado null de la expresión es el estado Null predeterminado de su tipo.Otherwise the null state of the expression is the default null state of its type.
object?[] array = ...;
if (array[0] != null)
{
// Warning: Converting null literal or possible null value to non-nullable type.
object o = array[0];
// Warning: Dereference of a possibly null reference.
Console.WriteLine(o.ToString());
}
// Nullable friendly pattern
if (array[0] is {} o)
{
Console.WriteLine(o.ToString());
}
Acceso baseBase access
Si B denota el tipo base del tipo envolvente, base.I tiene el mismo estado null que ((B)this).I y base[E] tiene el mismo estado null que ((B)this)[E] .If B denotes the base type of the enclosing type, base.I has the same null state as ((B)this).I and base[E] has the same null state as ((B)this)[E].
Expresiones predeterminadasDefault expressions
default(T) tiene el estado null en función de las propiedades del tipo T :default(T) has the null state based on the properties of the type T:
- Si el tipo es un tipo que no acepta valores NULL , tiene el estado null "not null"If the type is a nonnullable type then it has the null state "not null"
- De lo contrario, si el tipo es un parámetro de tipo, tiene el estado null "quizás default".Else if the type is a type parameter then it has the null state "maybe default"
- En caso contrario, tiene el estado null "quizás null"Else it has the null state "maybe null"
Expresiones condicionales nulas?.Null-conditional expressions ?.
Un null_conditional_expression tiene el estado Null basado en el tipo de expresión.A null_conditional_expression has the null state based on the expression type. Tenga en cuenta que esto hace referencia al tipo de null_conditional_expression , no al tipo original del miembro que se invoca:Note that this refers to the type of the null_conditional_expression, not the original type of the member being invoked:
- Si el tipo es un tipo de valor que acepta valores NULL , tiene el estado null "maybe null"If the type is a nullable value type then it has the null state "maybe null"
- De lo contrario, si el tipo es un parámetro de tipo que acepta valores NULL , tiene el estado null "quizás default".Else if the type is a nullable type parameter then it has the null state "maybe default"
- En caso contrario, tiene el estado null "quizás null"Else it has the null state "maybe null"
Expresiones de conversiónCast expressions
Si una expresión de conversión (T)E invoca una conversión definida por el usuario, el estado null de la expresión es el estado predeterminado NULL para el tipo de la conversión definida por el usuario.If a cast expression (T)E invokes a user-defined conversion, then the null state of the expression is the default null state for the type of the user-defined conversion. De lo contrario:Otherwise:
- Si
Tes un tipo de valor que no acepta valores NULL ,Ttiene el estado null "not null"IfTis a nonnullable value type thenThas the null state "not null" TDe lo contrario, si es un tipo de valor que acepta valores NULL ,Ttiene el estado null "maybe null"Else ifTis a nullable value type thenThas the null state "maybe null"- De lo contrario
T, si es un tipo que acepta valores NULL en el formularioU?U, donde es un parámetro de tipo,Ttiene el estado null "quizás default".Else ifTis a nullable type in the formU?whereUis a type parameter thenThas the null state "maybe default" - De lo contrario, si
Tes un tipo que acepta valores NULL yEtiene el estado null "maybe null" o "quizás default",Ttiene el estado null "maybe null"Else ifTis a nullable type, andEhas null state "maybe null" or "maybe default", thenThas the null state "maybe null" - De lo contrario, si
Tes un parámetro de tipo yEtiene el estado null "maybe null" o "quizás default",Ttiene el estado null "quizás default".Else ifTis a type parameter, andEhas null state "maybe null" or "maybe default", thenThas the null state "maybe default" - Else
Ttiene el mismo estado null queEElseThas the same null state asE
Operadores unarios y binariosUnary and binary operators
Si un operador unario o binario invoca a un operador definido por el usuario, el estado null de la expresión es el estado predeterminado NULL para el tipo del operador definido por el usuario.If a unary or binary operator invokes an user-defined operator then the null state of the expression is the default null state for the type of the user-defined operator. De lo contrario, es el estado null de la expresión.Otherwise it is the null state of the expression.
¿Algo especial de hacer para binario + en cadenas y delegados?Something special to do for binary + over strings and delegates?
Expresiones AwaitAwait expressions
El estado null de await E es el estado Null predeterminado de su tipo.The null state of await E is the default null state of its type.
El operador asThe as operator
El estado null de una E as T expresión depende primero de las propiedades del tipo T .The null state of an E as T expression depends first on properties of the type T. Si el tipo de T no admite valores NULL , el estado NULL es "not null".If the type of T is nonnullable then the null state is "not null". En caso contrario, el estado Null depende de la conversión del tipo de E al tipo T :Otherwise the null state depends on the conversion from the type of E to type T:
- Si la conversión es una identidad, una conversión boxing, una referencia implícita o una conversión implícita que acepta valores NULL, el estado NULL es el estado null de
EIf the conversion is an identity, boxing, implicit reference, or implicit nullable conversion, then the null state is the null state ofE TDe lo contrario, si es un parámetro de tipo, tiene el estado null "quizás default".Else ifTis a type parameter then it has the null state "maybe default"- En caso contrario, tiene el estado null "quizás null"Else it has the null state "maybe null"
Operador de uso combinado de nullThe null-coalescing operator
El estado null de E1 ?? E2 es el estado nulo de E2The null state of E1 ?? E2 is the null state of E2
El operador condicionalThe conditional operator
El estado null de E1 ? E2 : E3 se basa en el estado null de E2 y E3 :The null state of E1 ? E2 : E3 is based on the null state of E2 and E3:
- Si ambos son "not null", el estado NULL es "not null"If both are "not null" then the null state is "not null"
- De lo contrario, si es "quizás default", el estado NULL es "quizás default".Else if either is "maybe default" then the null state is "maybe default"
- De lo contrario, el estado NULL es "not null"Else the null state is "not null"
Expresiones de consultaQuery expressions
El estado null de una expresión de consulta es el estado Null predeterminado de su tipo.The null state of a query expression is the default null state of its type.
Trabajo adicional necesario aquíAdditional work needed here
Operadores de asignaciónAssignment operators
E1 = E2 y E1 op= E2 tienen el mismo estado null que E2 cuando se ha aplicado cualquier conversión implícita.E1 = E2 and E1 op= E2 have the same null state as E2 after any implicit conversions have been applied.
Expresiones que propagan el estado nullExpressions that propagate null state
(E)``checked(E)y unchecked(E) todos tienen el mismo estado null que E .(E), checked(E) and unchecked(E) all have the same null state as E.
Expresiones que nunca son NULLExpressions that are never null
El estado null de los siguientes formatos de expresión siempre es "not null":The null state of the following expression forms is always "not null":
thisaccessthisaccess- cadenas interpoladasinterpolated strings
newexpresiones (expresiones de objeto, delegado, objeto anónimo y creación de matriz)newexpressions (object, delegate, anonymous object and array creation expressions)- Expresiones
typeoftypeofexpressions - Expresiones
nameofnameofexpressions - funciones anónimas (métodos anónimos y expresiones lambda)anonymous functions (anonymous methods and lambda expressions)
- Expresiones permisivo nulasnull-forgiving expressions
- Expresiones
isisexpressions
Funciones anidadasNested functions
Las funciones anidadas (expresiones lambda y funciones locales) se tratan como métodos, excepto en lo que respecta a las variables capturadas.Nested functions (lambdas and local functions) are treated like methods, except in regards to their captured variables. El estado inicial de una variable capturada dentro de una función lambda o local es la intersección del estado que acepta valores NULL de la variable en todos los "usos" de esa función anidada o expresión lambda.The initial state of a captured variable inside a lambda or local function is the intersection of the nullable state of the variable at all the "uses" of that nested function or lambda. El uso de una función local es una llamada a esa función, o bien, donde se convierte en un delegado.A use of a local function is either a call to that function, or where it is converted to a delegate. El uso de una expresión lambda es el punto en el que se define en el origen.A use of a lambda is the point at which it is defined in source.
Inferencia de tiposType inference
variables locales con tipo implícito que aceptan valores NULLnullable implicitly typed local variables
var deduce un tipo anotado para los tipos de referencia y los parámetros de tipo que no están restringidos para ser un tipo de valor.var infers an annotated type for reference types, and type parameters that aren't constrained to be a value type.
Por ejemplo:For instance:
- en
var s = "";var, se deduce comostring?.invar s = "";thevaris inferred asstring?. - en
var t = new T();con una sin restriccionesTvar, se deduce comoT?.invar t = new T();with an unconstrainedTthevaris inferred asT?.
Inferencia de tipo genéricoGeneric type inference
La inferencia de tipos genéricos se ha mejorado para ayudar a decidir si los tipos de referencia deducidos deben admitir valores NULL o no.Generic type inference is enhanced to help decide whether inferred reference types should be nullable or not. Se trata de un mejor esfuerzo.This is a best effort. Puede producir advertencias con respecto a las restricciones de nulabilidad y puede dar lugar a advertencias que aceptan valores NULL cuando los tipos deducidos de la sobrecarga seleccionada se aplican a los argumentos.It may yield warnings regarding nullability constraints, and may lead to nullable warnings when the inferred types of the selected overload are applied to the arguments.
La primera faseThe first phase
Los tipos de referencia que aceptan valores NULL fluyen en los límites de las expresiones iniciales, como se describe a continuación.Nullable reference types flow into the bounds from the initial expressions, as described below. Además, null se introducen dos nuevos tipos de límites, es decir, y default .In addition, two new kinds of bounds, namely null and default are introduced. Su finalidad es llevar a cabo a través de null las apariciones de o default en las expresiones de entrada, lo que puede hacer que un tipo deducido acepte valores NULL, aunque no lo sea.Their purpose is to carry through occurrences of null or default in the input expressions, which may cause an inferred type to be nullable, even when it otherwise wouldn't. Esto funciona incluso para los tipos de valor que aceptan valores NULL, que se han mejorado para recoger la "nulación" en el proceso de inferencia.This works even for nullable value types, which are enhanced to pick up "nullness" in the inference process.
La determinación de los límites que se van a agregar en la primera fase se ha mejorado como se indica a continuación:The determination of what bounds to add in the first phase are enhanced as follows:
Si un argumento Ei tiene un tipo de referencia, el tipo que se U usa para la inferencia depende del estado null de, así Ei como de su tipo declarado:If an argument Ei has a reference type, the type U used for inference depends on the null state of Ei as well as its declared type:
- Si el tipo declarado es un tipo de referencia que no admite valores NULL
U0o un tipo de referencia que acepta valores NULLU0?, entoncesIf the declared type is a nonnullable reference typeU0or a nullable reference typeU0?then- Si el estado null de
Eies "not null", entoncesU``U0if the null state ofEiis "not null" thenUisU0 - Si el estado null de
Eies "quizás null", entoncesU``U0?if the null state ofEiis "maybe null" thenUisU0?
- Si el estado null de
- De lo contrario
Ei, si tiene un tipo declarado,Ues de ese tipo.Otherwise ifEihas a declared type,Uis that type - De lo
Eicontrarionull, si es,Uel enlace especialnullOtherwise ifEiisnullthenUis the special boundnull - De lo
Eicontrariodefault, si es,Uel enlace especialdefaultOtherwise ifEiisdefaultthenUis the special bounddefault - En caso contrario, no se realiza ninguna inferencia.Otherwise no inference is made.
Inferencias exactas, de límite superior y de límite inferiorExact, upper-bound and lower-bound inferences
En las inferencias del tipo U al tipo V , si V es un tipo de referencia que acepta valores NULL V0? , V0 se usa en lugar de V en las cláusulas siguientes.In inferences from the type U to the type V, if V is a nullable reference type V0?, then V0 is used instead of V in the following clauses.
- Si
Ves una de las variables de tipo sin corregir,Use agrega como un límite inferior, superior o inferior como antes.IfVis one of the unfixed type variables,Uis added as an exact, upper or lower bound as before - De lo contrario, si
Uesnullodefault, no se realiza ninguna inferencia.Otherwise, ifUisnullordefault, no inference is made - De lo contrario, si
Ues un tipo de referencia que acepta valores NULLU0?,U0se utiliza en lugar deUen las cláusulas posteriores.Otherwise, ifUis a nullable reference typeU0?, thenU0is used instead ofUin the subsequent clauses.
La esencia es que la nulabilidad que pertenece directamente a una de las variables de tipo sin Fixed se conserva en sus límites.The essence is that nullability that pertains directly to one of the unfixed type variables is preserved into its bounds. Por otra parte, para las inferencias que se recorren más en los tipos de origen y de destino, se omite la nulabilidad.For the inferences that recurse further into the source and target types, on the other hand, nullability is ignored. Puede o no coincidir, pero si no es así, se emitirá una advertencia más adelante si se elige la sobrecarga y se aplica.It may or may not match, but if it doesn't, a warning will be issued later if the overload is chosen and applied.
Corrección deFixing
Actualmente, la especificación no realiza un buen trabajo de describir lo que sucede cuando varios límites son convertibles entre sí, pero son diferentes.The spec currently does not do a good job of describing what happens when multiple bounds are identity convertible to each other, but are different. Esto puede ocurrir entre object y dynamic , entre tipos de tupla que solo difieren en los nombres de elemento, entre los tipos construidos en él y ahora también entre C y C? para los tipos de referencia.This may happen between object and dynamic, between tuple types that differ only in element names, between types constructed thereof and now also between C and C? for reference types.
Además, debemos propagar la "nulación" de las expresiones de entrada al tipo de resultado.In addition we need to propagate "nullness" from the input expressions to the result type.
Para controlar estos agregamos más fases para corregir, que ahora es:To handle these we add more phases to fixing, which is now:
- Recopile todos los tipos de todos los límites como candidatos, quitando
?de todos los tipos de referencia que aceptan valores NULLGather all the types in all the bounds as candidates, removing?from all that are nullable reference types - Eliminación de candidatos en función de los requisitos de los límites exactos, inferiores y superiores (mantenimiento
nullydefaultlímites)Eliminate candidates based on requirements of exact, lower and upper bounds (keepingnullanddefaultbounds) - Eliminación de candidatos que no tienen una conversión implícita a todos los demás candidatosEliminate candidates that do not have an implicit conversion to all the other candidates
- Si los candidatos restantes no tienen conversiones de identidad entre sí, se produce un error en la inferencia de tiposIf the remaining candidates do not all have identity conversions to one another, then type inference fails
- Combine los candidatos restantes como se describe a continuaciónMerge the remaining candidates as described below
- Si el candidato resultante es un tipo de referencia o un tipo de valor que no acepta valores NULL y todos los límites exactos o alguno de los límites inferiores son tipos de valor que aceptan valores NULL, tipos de referencia que aceptan valores NULL o
nulldefault,?se agregan al candidato resultante, lo que lo convierte en un tipo de valor que acepta valores NULL o un tipo de referencia.If the resulting candidate is a reference type or a nonnullable value type and all of the exact bounds or any of the lower bounds are nullable value types, nullable reference types,nullordefault, then?is added to the resulting candidate, making it a nullable value type or reference type.
La combinación se describe entre dos tipos candidatos.Merging is described between two candidate types. Es transitiva y conmutable, por lo que los candidatos se pueden combinar en cualquier orden con el mismo resultado final.It is transitive and commutative, so the candidates can be merged in any order with the same ultimate result. No se define si los dos tipos candidatos no son una identidad convertible entre sí.It is undefined if the two candidate types are not identity convertible to each other.
La función Merge toma dos tipos de candidatos y una dirección ( + o - ):The Merge function takes two candidate types and a direction (+ or -):
- Merge(
T,T, d) = TMerge(T,T, d) = T - Merge(
S,T?, + ) = Merge(S?,T, + ) = Merge(S,T, + )?Merge(S,T?, +) = Merge(S?,T, +) = Merge(S,T, +)? - Merge(
S,T?, - ) = Merge(S?,T, - ) = Merge(S,T, - )Merge(S,T?, -) = Merge(S?,T, -) = Merge(S,T, -) - Merge(
C<S1,...,Sn>,C<T1,...,Tn>, + ) =C<Merge(S1,T1, D1),...,Merge(Sn,Tn, DN)>, dondeMerge(C<S1,...,Sn>,C<T1,...,Tn>, +) =C<Merge(S1,T1, d1),...,Merge(Sn,Tn, dn)>, wheredi= + Si eliparámetro de tipo TH deC<...>es covariantedi= + if thei'th type parameter ofC<...>is covariantdi= - Si eliparámetro de tipo ' th ofC<...>es compensa-or invariabledi= - if thei'th type parameter ofC<...>is contra- or invariant
- Merge(
C<S1,...,Sn>,C<T1,...,Tn>, - ) =C<Merge(S1,T1, D1),...,Merge(Sn,Tn, DN)>, dondeMerge(C<S1,...,Sn>,C<T1,...,Tn>, -) =C<Merge(S1,T1, d1),...,Merge(Sn,Tn, dn)>, wheredi= - Si eliparámetro de tipo TH deC<...>es covariantedi= - if thei'th type parameter ofC<...>is covariantdi= + Si eliparámetro de tipo ' th ofC<...>es compensa-or invariabledi= + if thei'th type parameter ofC<...>is contra- or invariant
- Merge(
(S1 s1,..., Sn sn),(T1 t1,..., Tn tn), d) =(Merge(S1,T1, d)n1,...,Merge(Sn,Tn, d)nn), dondeMerge((S1 s1,..., Sn sn),(T1 t1,..., Tn tn), d) =(Merge(S1,T1, d)n1,...,Merge(Sn,Tn, d)nn), whereniestá ausente sisiytidifieren, o si ambos están ausentesniis absent ifsiandtidiffer, or if both are absentniessisisiytison iguales.niissiifsiandtiare the same
- Merge(
object,dynamic) = Merge(dynamic,object) =dynamicMerge(object,dynamic) = Merge(dynamic,object) =dynamic