Spécification des types référence NullableNullable Reference Types Specification

Il s’agit d’un travail en cours : plusieurs parties sont manquantes ou incomplètes.This is a work in progress - several parts are missing or incomplete.

Cette fonctionnalité ajoute deux nouveaux types de types Nullable (types de référence Nullable et types génériques Nullable) aux types valeur Nullable existants, et introduit une analyse de fluide statique à des fins de sécurité null.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.

SyntaxSyntax

Types référence Nullable et paramètres de type NullableNullable reference types and nullable type parameters

Les types référence Nullable et les paramètres de type Nullable ont la même syntaxe T? que la forme abrégée des types valeur Nullable, mais n’ont pas de forme longue correspondante.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.

Dans le cadre de la spécification, la nullable_type production actuelle est renommée nullable_value_type , et les nullable_reference_type nullable_type_parameter productions sont ajoutées :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
    ;

Le non_nullable_reference_type dans un nullable_reference_type doit être un type référence non null (classe, interface, délégué ou tableau).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_parameterDans nullable_type_parameter doit être un paramètre de type qui n’est pas imposé comme étant un type valeur.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.

Les types référence Nullable et les paramètres de type Nullable ne peuvent pas se produire aux emplacements suivants :Nullable reference types and nullable type parameters cannot occur in the following positions:

  • comme une classe ou une interface de baseas a base class or interface
  • en tant que récepteur d’un member_accessas the receiver of a member_access
  • comme type dans un object_creation_expressionas the type in an object_creation_expression
  • comme delegate_type dans un delegate_creation_expressionas the delegate_type in a delegate_creation_expression
  • comme type dans un is_expression , un catch_clause ou un type_patternas the type in an is_expression, a catch_clause or a type_pattern
  • en tant que interface dans un nom de membre d’interface qualifié completas the interface in a fully qualified interface member name

Un avertissement est fourni sur un nullable_reference_type et nullable_type_parameter dans un contexte d’annotation Nullable désactivé .A warning is given on a nullable_reference_type and nullable_type_parameter in a disabled nullable annotation context.

class et class? contrainteclass and class? constraint

La class contrainte a un équivalent Nullable class? :The class constraint has a nullable counterpart class?:

primary_constraint
    : ...
    | 'class' '?'
    ;

Un paramètre de type restreint avec class (dans un contexte d’annotation activé ) doit être instancié avec un type référence qui n’est pas null.A type parameter constrained with class (in an enabled annotation context) must be instantiated with a nonnullable reference type.

Un paramètre de type restreint avec class? (ou class dans un contexte d’annotation désactivé ) peut être instancié avec un type de référence Nullable ou non 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.

Un avertissement est fourni sur une class? contrainte dans un contexte d’annotation désactivé .A warning is given on a class? constraint in a disabled annotation context.

notnull restrictionsnotnull constraint

Un paramètre de type restreint avec notnull ne peut pas être un type Nullable (type valeur Nullable, type référence Nullable ou paramètre de type Nullable).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 restrictionsdefault constraint

La default contrainte peut être utilisée sur une substitution de méthode ou une implémentation explicite pour lever l’ambiguïté T? « paramètre de type Nullable » de « type valeur Nullable » ( 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>). En l’absence de la default contrainte, une T? syntaxe dans une implémentation de substitution ou explicite est interprétée comme Nullable<T>Lacking the default constraint a T? syntax in an override or explicit implementation will be interpreted as Nullable<T>

Voir https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/unconstrained-type-parameter-annotations.md#default-constraintSee https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/unconstrained-type-parameter-annotations.md#default-constraint

Opérateur null-indulgent avecThe null-forgiving operator

L’opérateur de postconnexion ! est appelé opérateur null-indulgent avec.The post-fix ! operator is called the null-forgiving operator. Il peut être appliqué à un primary_expression ou au sein d’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
    : '!'
    ;

Par exemple :For example:

var v = expr!;
expr!.M();
_ = a?.b!.c;

primary_expressionEt null_conditional_operations_no_suppression doivent être d’un type Nullable.The primary_expression and null_conditional_operations_no_suppression must be of a nullable type.

L’opérateur postfix n' ! a aucun effet d’exécution, il prend la valeur du résultat de l’expression sous-jacente.The postfix ! operator has no runtime effect - it evaluates to the result of the underlying expression. Son seul rôle consiste à modifier l’État null de l’expression en « not null » et à limiter les avertissements en fonction de son utilisation.Its only role is to change the null state of the expression to "not null", and to limit warnings given on its use.

Directives de compilateur NullableNullable compiler directives

#nullable les directives contrôlent l’annotation Nullable et les contextes d’avertissement.#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 les directives sont développées pour permettre la modification du contexte d’avertissement Nullable :#pragma warning directives are expanded to allow changing the nullable warning context:

pragma_warning_body
    : ...
    | 'warning' whitespace warning_action whitespace 'nullable'
    ;

Par exemple :For example:

#pragma warning disable nullable

Contextes nullablesNullable contexts

Chaque ligne de code source a un contexte d’annotation Nullable et un contexte d’avertissement Nullable.Every line of source code has a nullable annotation context and a nullable warning context. Ils contrôlent si les annotations Nullable ont un effet et si les avertissements de possibilité de valeur NULL sont fournis.These control whether nullable annotations have effect, and whether nullability warnings are given. Le contexte d’annotation d’une ligne donnée est désactivé ou activé.The annotation context of a given line is either disabled or enabled. Le contexte d’avertissement d’une ligne donnée est désactivé ou activé.The warning context of a given line is either disabled or enabled.

Les deux contextes peuvent être spécifiés au niveau du projet (en dehors du code source C#), ou n’importe où dans un fichier source via des #nullable directives de préprocesseur.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 aucun paramètre de niveau projet n’est fourni, la valeur par défaut est pour que les deux contextes soient désactivés.If no project level settings are provided the default is for both contexts to be disabled.

La #nullable directive contrôle les contextes d’annotation et d’avertissement dans le texte source et a priorité sur les paramètres au niveau du projet.The #nullable directive controls the annotation and warning contexts within the source text, and take precedence over the project-level settings.

Une directive définit le ou les contexte (s) qu’elle contrôle pour les lignes de code suivantes, jusqu’à ce qu’une autre directive la remplace, ou jusqu’à la fin du fichier source.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.

L’effet des directives est le suivant :The effect of the directives is as follows:

  • #nullable disable: Définit l’annotation Nullable et les contextes d’avertissement sur désactivé#nullable disable: Sets the nullable annotation and warning contexts to disabled
  • #nullable enable: Définit l’annotation Nullable et les contextes d’avertissement sur activé#nullable enable: Sets the nullable annotation and warning contexts to enabled
  • #nullable restore: Restaure l’annotation Nullable et les contextes d’avertissement dans les paramètres du projet#nullable restore: Restores the nullable annotation and warning contexts to project settings
  • #nullable disable annotations: Définit le contexte d’annotation Nullable sur désactivé#nullable disable annotations: Sets the nullable annotation context to disabled
  • #nullable enable annotations: Définit le contexte d’annotation Nullable sur activé#nullable enable annotations: Sets the nullable annotation context to enabled
  • #nullable restore annotations: Restaure le contexte d’annotation Nullable aux paramètres du projet#nullable restore annotations: Restores the nullable annotation context to project settings
  • #nullable disable warnings: Définit le contexte d’avertissement Nullable sur désactivé#nullable disable warnings: Sets the nullable warning context to disabled
  • #nullable enable warnings: Définit le contexte d’avertissement Nullable sur activé#nullable enable warnings: Sets the nullable warning context to enabled
  • #nullable restore warnings: Restaure le contexte d’avertissement Nullable aux paramètres du projet#nullable restore warnings: Restores the nullable warning context to project settings

Nullabilité des typesNullability of types

Un type donné peut avoir l’un des trois nullabilities : oublie, non null et Nullable.A given type can have one of three nullabilities: oblivious, nonnullable, and nullable.

Les types non null peuvent provoquer des avertissements si une null valeur potentielle leur est assignée.Nonnullable types may cause warnings if a potential null value is assigned to them. Toutefois, les types oublie et Nullable sont «null-assignables» et peuvent avoir des null valeurs qui leur sont assignées sans avertissements.Oblivious and nullable types, however, are "null-assignable" and can have null values assigned to them without warnings.

Les valeurs de oublie et de types non nullables peuvent être déréférencées ou assignées sans avertissements.Values of oblivious and nonnullable types can be dereferenced or assigned without warnings. Toutefois, les valeurs de types Nullable sont «yield null» et peuvent provoquer des avertissements lorsqu’ils sont déréférencés ou assignés sans vérification de valeur null correcte.Values of nullable types, however, are "null-yielding" and may cause warnings when dereferenced or assigned without proper null checking.

L' État NULL par défaut d’un type qui donne NULL est « peut-être null » ou « peut-être par défaut ».The default null state of a null-yielding type is "maybe null" or "maybe default". L’État NULL par défaut d’un type qui ne génère pas de valeur null est « not null ».The default null state of a non-null-yielding type is "not null".

Le genre de type et le contexte d’annotation Nullable qu’il contient se trouvent dans déterminer sa possibilité de valeur NULL :The kind of type and the nullable annotation context it occurs in determine its nullability:

  • Un type valeur S non null est toujours non nullA nonnullable value type S is always nonnullable
  • Un type valeur Nullable S? est toujours NullableA nullable value type S? is always nullable
  • Un type référence non annoté C dans un contexte d’annotation désactivé est oublieAn unannotated reference type C in a disabled annotation context is oblivious
  • Un type référence non annoté C dans un contexte d’annotation activé n’est pas nullAn unannotated reference type C in an enabled annotation context is nonnullable
  • Un type de référence Nullable C? est Nullable (mais un avertissement peut être généré dans un contexte d’annotation désactivé )A nullable reference type C? is nullable (but a warning may be yielded in a disabled annotation context)

Les paramètres de type prennent également en compte les contraintes :Type parameters additionally take their constraints into account:

  • Un paramètre de type T où toutes les contraintes (le cas échéant) sont des types Nullable ou la class? contrainte accepte la valeur nullA type parameter T where all constraints (if any) are either nullable types or the class? constraint is nullable
  • Un paramètre de type T dans lequel au moins une contrainte est oublie ou non null , ou l’une struct des class contraintes ou notnull estA type parameter T where at least one constraint is either oblivious or nonnullable or one of the struct or class or notnull constraints is
    • oublie dans un contexte d’annotation désactivéoblivious in a disabled annotation context
    • non null dans un contexte d’annotation activénonnullable in an enabled annotation context
  • Un paramètre de type Nullable T? est Nullable, mais un avertissement est généré dans un contexte d’annotation désactivé si T n’est pas un type valeurA nullable type parameter T? is nullable, but a warning is yielded in a disabled annotation context if T isn't a value type

Oublie et non nullOblivious vs nonnullable

Un type est considéré comme ayant lieu dans un contexte d’annotation donné lorsque le dernier jeton du type est dans ce contexte.A type is deemed to occur in a given annotation context when the last token of the type is within that context.

Si un type de référence donné C dans le code source est interprété comme oublie ou non null, dépend du contexte d’annotation de ce code source.Whether a given reference type C in source code is interpreted as oblivious or nonnullable depends on the annotation context of that source code. Mais une fois qu’elle est établie, elle est considérée comme faisant partie de ce type et « suit », par exemple, lors de la substitution des arguments de type générique.But once established, it is considered part of that type, and "travels with it" e.g. during substitution of generic type arguments. C’est comme s’il s’agissait d’une annotation telle que ? sur le type, mais invisible.It is as if there is an annotation like ? on the type, but invisible.

ContraintesConstraints

Les types de référence Nullable peuvent être utilisés en tant que contraintes génériques.Nullable reference types can be used as generic constraints.

class? est une nouvelle contrainte qui signale « peut-être un type de référence Nullable », alors que class dans un contexte d’annotation activé désigne « type référence non null ».class? is a new constraint denoting "possibly nullable reference type", whereas class in an enabled annotation context denotes "nonnullable reference type".

default est une nouvelle contrainte qui signale un paramètre de type qui n’est pas connu comme étant une référence ou un type valeur.default is a new constraint denoting a type parameter that isn't known to be a reference or value type. Elle ne peut être utilisée que sur des méthodes substituées et explicitement implémentées.It can only be used on overridden and explicitly implemented methods. Avec cette contrainte, T? correspond à un paramètre de type Nullable, par opposition à un raccourci pour Nullable<T> .With this constraint, T? means a nullable type parameter, as opposed to being a shorthand for Nullable<T>.

notnull est une nouvelle contrainte qui désigne un paramètre de type qui n’est pas null.notnull is a new constraint denoting a type parameter that is nonnullable.

La possibilité de valeur null d’un argument de type ou d’une contrainte n’a pas d’incidence sur la satisfaction de la contrainte par le type, sauf si ce n’est pas le cas aujourd’hui (les types valeur Nullable ne répondent pas à la struct contrainte).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). Toutefois, si l’argument de type ne satisfait pas aux exigences de possibilité de valeur null de la contrainte, un avertissement peut être fourni.However, if the type argument does not satisfy the nullability requirements of the constraint, a warning may be given.

État null et suivi nullNull state and null tracking

Chaque expression d’un emplacement source donné a un État null, ce qui indique s’il est supposé avoir une valeur null.Every expression in a given source location has a null state, which indicated whether it is believed to potentially evaluate to null. L’État null est « not null », « peut-être null » ou « peut-être par défaut ».The null state is either "not null", "maybe null", or "maybe default". L’État null est utilisé pour déterminer si un avertissement doit être fourni à propos des conversions et déréférencements non sécurisés par des valeurs NULL.The null state is used to determine whether a warning should be given about null-unsafe conversions and dereferences.

La distinction entre « peut-être null » et « peut-être par défaut » est subtile et s’applique aux paramètres de type.The distinction between "maybe null" and "maybe default" is subtle and applies to type parameters. La distinction est qu’un paramètre T de type qui a l’État « peut-être null » signifie que la valeur est dans le domaine des valeurs autorisées pour, T mais cette valeur légale peut inclure 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. Lorsque la valeur par défaut est « peut-être », cela signifie que la valeur peut être en dehors du domaine légal des valeurs pour T .Where as a "maybe default" means that the value may be outside the legal domain of values for T.

Exemple :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);
}

Suivi de valeurs NULL pour les variablesNull tracking for variables

Pour certaines expressions qui désignent des variables, des champs ou des propriétés, l’État null est suivi entre les occurrences, en fonction des assignations à celles-ci, les tests effectués sur ceux-ci et le workflow de contrôle entre eux.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. Cela est similaire à la façon dont l’assignation définie est suivie pour les variables.This is similar to how definite assignment is tracked for variables. Les expressions suivies sont les suivantes :The tracked expressions are the ones of the following form:

tracked_expression
    : simple_name
    | this
    | base
    | tracked_expression '.' identifier
    ;

Où les identificateurs désignent des champs ou des propriétés.Where the identifiers denote fields or properties.

L’État null des variables suivies est « not null » dans le code inaccessible.The null state for tracked variables is "not null" in unreachable code. Cela suit d’autres décisions concernant le code inaccessible, comme considérer tous les variables locales comme étant assignées définitivement.This follows other decisions around unreachable code like considering all locals to be definitely assigned.

Décrire les transitions d’État null similaires à l’assignation définieDescribe null state transitions similar to definite assignment

État null pour les expressionsNull state for expressions

L’État null d’une expression est dérivé de son formulaire et de son type, et de l’État null des variables qui y sont impliquées.The null state of an expression is derived from its form and type, and from the null state of variables involved in it.

LittérauxLiterals

L’État null d’un null littéral dépend du type de cible de l’expression.The null state of a null literal depends on the target type of the expression. Si le type cible est un paramètre de type restreint à un type référence, il s’agit de « peut-être par défaut ».If the target type is a type parameter constrained to a reference type then it's "maybe default". Dans le cas contraire, il s’agit de « peut-être null ».Otherwise it is "maybe null".

L’État null d’un default littéral dépend du type de cible du default littéral.The null state of a default literal depends on the target type of the default literal. Un default littéral avec le type de cible T a le même État null que l' default(T) expression.A default literal with target type T has the same null state as the default(T) expression.

L’État null de tout autre littéral est « not null ».The null state of any other literal is "not null".

Noms simplesSimple names

Si un simple_name n’est pas classé comme une valeur, son état null est « not null ».If a simple_name is not classified as a value, its null state is "not null". Dans le cas contraire, il s’agit d’une expression suivie, et son état null est son état de suivi null à cet emplacement source.Otherwise it is a tracked expression, and its null state is its tracked null state at this source location.

Accès au membreMember access

Si un member_access n’est pas classé comme une valeur, son état null est « not null ».If a member_access is not classified as a value, its null state is "not null". Sinon, s’il s’agit d’une expression suivie, son état null est son état de suivi null à cet emplacement source.Otherwise, if it is a tracked expression, its null state is its tracked null state at this source location. Dans le cas contraire, son état null est l’État NULL par défaut de son type.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;
}

Appel d’expressionsInvocation expressions

Si un invocation_expression appelle un membre qui est déclaré avec un ou plusieurs attributs pour un comportement spécial Null, l’État null est déterminé par ces attributs.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. Dans le cas contraire, l’État null de l’expression est l’État NULL par défaut de son type.Otherwise the null state of the expression is the default null state of its type.

L’État null d’un invocation_expression n’est pas suivi par le compilateur.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) {  }

Accès aux élémentsElement access

Si un element_access appelle un indexeur qui est déclaré avec un ou plusieurs attributs pour un comportement spécial Null, l’État null est déterminé par ces attributs.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. Dans le cas contraire, l’État null de l’expression est l’État NULL par défaut de son type.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());
}

Accès de baseBase access

Si B indique le type de base du type englobant, base.I a le même État null que ((B)this).I et base[E] a le même État 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].

Expressions par défautDefault expressions

default(T) a l’État null en fonction des propriétés du type T :default(T) has the null state based on the properties of the type T:

  • Si le type est un type non null , il a l’État null « not null ».If the type is a nonnullable type then it has the null state "not null"
  • Sinon, si le type est un paramètre de type, il a l’État NULL « peut-être par défaut ».Else if the type is a type parameter then it has the null state "maybe default"
  • Sinon, il a l’État NULL « peut-être null »Else it has the null state "maybe null"

Expressions conditionnelles null ?.Null-conditional expressions ?.

null_conditional_expressionA l’État null selon le type d’expression.A null_conditional_expression has the null state based on the expression type. Notez que cela fait référence au type du null_conditional_expression , et non au type d’origine du membre appelé :Note that this refers to the type of the null_conditional_expression, not the original type of the member being invoked:

  • Si le type est un type valeur Nullable , il a l’État NULL « peut-être null »If the type is a nullable value type then it has the null state "maybe null"
  • Sinon, si le type est un paramètre de type Nullable , il a l’État NULL « peut-être par défaut ».Else if the type is a nullable type parameter then it has the null state "maybe default"
  • Sinon, il a l’État NULL « peut-être null »Else it has the null state "maybe null"

Expressions castCast expressions

Si une expression de Cast (T)E appelle une conversion définie par l’utilisateur, l’État null de l’expression est l’État NULL par défaut pour le type de la conversion définie par l’utilisateur.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. Sinon :Otherwise:

  • Si T est un type valeur non null , T a alors l’État null « not null »If T is a nonnullable value type then T has the null state "not null"
  • Sinon T , si est un type valeur Nullable , T a l’État NULL « peut-être null »Else if T is a nullable value type then T has the null state "maybe null"
  • Sinon T , si est un type Nullable dans le formulaire U?U est un paramètre de type, T a alors l’État NULL « peut-être par défaut »Else if T is a nullable type in the form U? where U is a type parameter then T has the null state "maybe default"
  • Sinon, si T est un type Nullable et E a un État NULL « peut-être null » ou « peut-être par défaut », T l’État null est « peut-être null ».Else if T is a nullable type, and E has null state "maybe null" or "maybe default", then T has the null state "maybe null"
  • Sinon, si T est un paramètre de type et qu’il E a l’État NULL « peut-être null » ou « peut-être par défaut », T l’État null est « peut-être par défaut ».Else if T is a type parameter, and E has null state "maybe null" or "maybe default", then T has the null state "maybe default"
  • Else T a le même État null que EElse T has the same null state as E

Opérateurs unaires et binairesUnary and binary operators

Si un opérateur unaire ou binaire appelle un opérateur défini par l’utilisateur, l’État null de l’expression est l’État NULL par défaut pour le type de l’opérateur défini par l’utilisateur.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. Dans le cas contraire, il s’agit de l’État null de l’expression.Otherwise it is the null state of the expression.

Quoi faire pour les chaînes binaires + et les délégués ?Something special to do for binary + over strings and delegates?

Expressions awaitAwait expressions

L’État null de await E est l’État NULL par défaut de son type.The null state of await E is the default null state of its type.

L’opérateur asThe as operator

L’État null d’une E as T expression dépend d’abord des propriétés du type T .The null state of an E as T expression depends first on properties of the type T. Si le type de T n’est pas null , l’État null est « not null ».If the type of T is nonnullable then the null state is "not null". Dans le cas contraire, l’État null dépend de la conversion du type de E en type T :Otherwise the null state depends on the conversion from the type of E to type T:

  • Si la conversion est une identité, une conversion boxing, une référence implicite ou une conversion Nullable implicite, l’État null est l’État null de EIf the conversion is an identity, boxing, implicit reference, or implicit nullable conversion, then the null state is the null state of E
  • Sinon, si T est un paramètre de type, il a l’État NULL « peut-être par défaut »Else if T is a type parameter then it has the null state "maybe default"
  • Sinon, il a l’État NULL « peut-être null »Else it has the null state "maybe null"

Opérateur de fusion NullThe null-coalescing operator

L’État null de E1 ?? E2 est l’État null de E2The null state of E1 ?? E2 is the null state of E2

l'opérateur conditionnel ;The conditional operator

L’État null de E1 ? E2 : E3 est basé sur l’État null de E2 et E3 :The null state of E1 ? E2 : E3 is based on the null state of E2 and E3:

  • Si les deux sont « not null », l’État null est « not null ».If both are "not null" then the null state is "not null"
  • Sinon, si est « peut-être par défaut », l’État null est « peut-être par défaut »Else if either is "maybe default" then the null state is "maybe default"
  • Sinon, l’État null est « not null »Else the null state is "not null"

Expressions de requêteQuery expressions

L’État null d’une expression de requête est l’État NULL par défaut de son type.The null state of a query expression is the default null state of its type.

Travail supplémentaire nécessaire iciAdditional work needed here

Opérateurs d’assignationAssignment operators

E1 = E2 et E1 op= E2 ont le même État null qu' E2 après l’application de toutes les conversions implicites.E1 = E2 and E1 op= E2 have the same null state as E2 after any implicit conversions have been applied.

Expressions qui propagent l’État nullExpressions that propagate null state

(E), checked(E) et unchecked(E) ont tous le même État null que E .(E), checked(E) and unchecked(E) all have the same null state as E.

Expressions qui ne sont jamais nullExpressions that are never null

L’État null des formulaires d’expression suivants est toujours « not null » :The null state of the following expression forms is always "not null":

  • this Accès Transact-SQLthis access
  • chaînes interpoléesinterpolated strings
  • new expressions (objets, délégués, objets anonymes et expressions de création de tableau)new expressions (object, delegate, anonymous object and array creation expressions)
  • Expressions typeoftypeof expressions
  • Expressions nameofnameof expressions
  • fonctions anonymes (méthodes anonymes et expressions lambda)anonymous functions (anonymous methods and lambda expressions)
  • expressions null-indulgent avecnull-forgiving expressions
  • Expressions isis expressions

Fonctions imbriquéesNested functions

Les fonctions imbriquées (expressions lambda et fonctions locales) sont traitées comme des méthodes, sauf en ce qui concerne leurs variables capturées.Nested functions (lambdas and local functions) are treated like methods, except in regards to their captured variables. L’état initial d’une variable capturée à l’intérieur d’une fonction lambda ou locale est l’intersection de l’État Nullable de la variable à toutes les « utilisations » de cette fonction imbriquée ou de cette expression 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. L’utilisation d’une fonction locale est un appel à cette fonction ou l’endroit où elle est convertie en délégué.A use of a local function is either a call to that function, or where it is converted to a delegate. L’utilisation d’une expression lambda est le point auquel elle est définie dans la source.A use of a lambda is the point at which it is defined in source.

Inférence de typeType inference

variables locales implicitement typées Nullablenullable implicitly typed local variables

var déduit un type annoté pour les types référence et les paramètres de type qui ne sont pas limités comme étant un type valeur.var infers an annotated type for reference types, and type parameters that aren't constrained to be a value type. Exemple :For instance:

  • dans var s = ""; , var est déduit en tant que string? .in var s = ""; the var is inferred as string?.
  • dans var t = new T(); avec un sans contrainte T var , est déduit en tant que T? .in var t = new T(); with an unconstrained T the var is inferred as T?.

Inférence de type génériqueGeneric type inference

L’inférence de type générique est améliorée pour déterminer si les types référence déduits doivent avoir la valeur null ou non.Generic type inference is enhanced to help decide whether inferred reference types should be nullable or not. C’est un meilleur effort.This is a best effort. Elle peut générer des avertissements concernant les contraintes de possibilité de valeur null et peut entraîner des avertissements Nullable lorsque les types inférés de la surcharge sélectionnée sont appliqués aux arguments.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 première phaseThe first phase

Les types référence Nullable circulent dans les limites des expressions initiales, comme décrit ci-dessous.Nullable reference types flow into the bounds from the initial expressions, as described below. En outre, deux nouveaux types de limites, à savoir null et default sont introduits.In addition, two new kinds of bounds, namely null and default are introduced. Leur but est de traverser des occurrences de null ou default dans les expressions d’entrée, ce qui peut entraîner la création d’une valeur null dans un type inféré, même si ce n’est pas le cas.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. Cela fonctionne même pour les types valeur Nullable, qui sont améliorés pour récupérer la « nullité » dans le processus d’inférence.This works even for nullable value types, which are enhanced to pick up "nullness" in the inference process.

La détermination des limites à ajouter dans la première phase est améliorée comme suit :The determination of what bounds to add in the first phase are enhanced as follows:

Si un argument Ei a un type référence, le type U utilisé pour l’inférence dépend de l’État null de, ainsi Ei que de son type déclaré :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 le type déclaré est un type référence non null U0 ou un type référence Nullable U0? , alorsIf the declared type is a nonnullable reference type U0 or a nullable reference type U0? then
    • Si l’État null de Ei est « not null », alors U est U0if the null state of Ei is "not null" then U is U0
    • Si l’État null de Ei est « peut-être null », alors U est U0?if the null state of Ei is "maybe null" then U is U0?
  • Sinon Ei , si a un type déclaré, U est ce typeOtherwise if Ei has a declared type, U is that type
  • Sinon, si Ei est null ensuite U la limite spéciale nullOtherwise if Ei is null then U is the special bound null
  • Sinon, si Ei est default ensuite U la limite spéciale defaultOtherwise if Ei is default then U is the special bound default
  • Sinon, aucune inférence n’est effectuée.Otherwise no inference is made.

Inférences exactes, limites supérieures et limites inférieuresExact, upper-bound and lower-bound inferences

Dans les inférences du type U vers le type V , si V est un type référence Nullable V0? , V0 est utilisé à la place de V dans les clauses suivantes.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 V est l’une des variables de type non fixed, U est ajouté comme limite exacte, supérieure ou inférieure comme avantIf V is one of the unfixed type variables, U is added as an exact, upper or lower bound as before
  • Sinon, si U est null ou default , aucune inférence n’est effectuéeOtherwise, if U is null or default, no inference is made
  • Sinon, si U est un type référence Nullable U0? , U0 est utilisé U à la place de dans les clauses suivantes.Otherwise, if U is a nullable reference type U0?, then U0 is used instead of U in the subsequent clauses.

L’essence est que la possibilité de valeur null liée directement à l’une des variables de type non Fixed est conservée dans ses limites.The essence is that nullability that pertains directly to one of the unfixed type variables is preserved into its bounds. Pour les inférences qui parcourent davantage les types source et cible, en revanche, la possibilité de valeur null est ignorée.For the inferences that recurse further into the source and target types, on the other hand, nullability is ignored. Il est possible qu’il ne corresponde pas, mais si ce n’est pas le cas, un avertissement est émis ultérieurement si la surcharge est choisie et appliquée.It may or may not match, but if it doesn't, a warning will be issued later if the overload is chosen and applied.

Résolution Fixing

Actuellement, la spécification ne permet pas de décrire ce qui se produit lorsque plusieurs limites sont convertibles de l’identité les unes des autres, mais sont différentes.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. Cela peut se produire entre object et dynamic , entre les types tuple qui diffèrent uniquement dans les noms d’éléments, entre les types construits et maintenant entre C et C? pour les types référence.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.

En outre, nous devons propager la « valeur null » des expressions d’entrée vers le type de résultat.In addition we need to propagate "nullness" from the input expressions to the result type.

Pour gérer ces éléments, nous allons ajouter des phases à la résolution, ce qui est maintenant :To handle these we add more phases to fixing, which is now:

  1. Rassemblez tous les types dans toutes les limites en tant que candidats, en supprimant ? de tous les types de référence NullableGather all the types in all the bounds as candidates, removing ? from all that are nullable reference types
  2. Éliminer les candidats en fonction des exigences relatives aux limites exactes, inférieures et supérieures (maintien null et default limites)Eliminate candidates based on requirements of exact, lower and upper bounds (keeping null and default bounds)
  3. Éliminer les candidats qui n’ont pas de conversion implicite vers tous les autres candidatsEliminate candidates that do not have an implicit conversion to all the other candidates
  4. Si les candidats restants n’ont pas tous une conversion d’identité entre eux, l’inférence de type échoueIf the remaining candidates do not all have identity conversions to one another, then type inference fails
  5. Fusionnez les candidats restants comme indiqué ci-dessous.Merge the remaining candidates as described below
  6. Si le candidat résultant est un type référence ou un type valeur non null et que toutes les limites exactes ou une des limites inférieures sont des types valeur Nullable, des types référence Nullable ou null default , ? est ajouté au candidat résultant, ce qui en fait un type valeur Nullable ou un type référence.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, null or default, then ? is added to the resulting candidate, making it a nullable value type or reference type.

La fusion est décrite entre deux types candidats.Merging is described between two candidate types. Elle est transitive et transmutative, de sorte que les candidats peuvent être fusionnés dans n’importe quel ordre avec le même résultat final.It is transitive and commutative, so the candidates can be merged in any order with the same ultimate result. Elle n’est pas définie si les deux types candidats ne sont pas convertibles en identité.It is undefined if the two candidate types are not identity convertible to each other.

La fonction Merge accepte deux types candidats et une direction ( + ou - ) :The Merge function takes two candidate types and a direction (+ or -):

  • Fusionner( T , T , d) = TMerge(T, T, d) = T
  • Merge( S , T? , + ) = fusion( S? , T , + ) = Merge( S , T , + )?Merge(S, T?, +) = Merge(S?, T, +) = Merge(S, T, +)?
  • Merge( S , T? , - ) = fusion( S? , T , - ) = Merge( S , T , - )Merge(S, T?, -) = Merge(S?, T, -) = Merge(S, T, -)
  • Merge( C<S1,...,Sn> , C<T1,...,Tn> , + ) = C< fusion( S1 , T1 D1) ,..., fusionner( Sn , Tn , DN) > , Merge(C<S1,...,Sn>, C<T1,...,Tn>, +) = C<Merge(S1, T1, d1),...,Merge(Sn, Tn, dn)>, where
    • di = + Si le i paramètre de type « TH » de C<...> est covariantdi = + if the i'th type parameter of C<...> is covariant
    • di = - Si le i paramètre de type « TH » de C<...> est en contre-ou invariantdi = - if the i'th type parameter of C<...> is contra- or invariant
  • Merge( C<S1,...,Sn> , C<T1,...,Tn> , - ) = C< fusion( S1 , T1 D1) ,..., fusionner( Sn , Tn , DN) > , Merge(C<S1,...,Sn>, C<T1,...,Tn>, -) = C<Merge(S1, T1, d1),...,Merge(Sn, Tn, dn)>, where
    • di = - Si le i paramètre de type « TH » de C<...> est covariantdi = - if the i'th type parameter of C<...> is covariant
    • di = + Si le i paramètre de type « TH » de C<...> est en contre-ou invariantdi = + if the i'th type parameter of C<...> is contra- or invariant
  • Merge( (S1 s1,..., Sn sn) , (T1 t1,..., Tn tn) , d) = ( fusion( S1 , T1 , d) n1,..., fusion( Sn , Tn , d) nn) , Merge((S1 s1,..., Sn sn), (T1 t1,..., Tn tn), d) = (Merge(S1, T1, d)n1,...,Merge(Sn, Tn, d) nn), where
    • ni est absent si si et ti diffère, ou si les deux sont absentsni is absent if si and ti differ, or if both are absent
    • ni est si si si et ti sont identiquesni is si if si and ti are the same
  • Merge( object , dynamic ) = fusion( dynamic , object ) = dynamicMerge(object, dynamic) = Merge(dynamic, object) = dynamic

AvertissementsWarnings

Attribution de valeur null potentiellePotential null assignment

Déréférencement null potentielPotential null dereference

Incompatibilité des valeurs null de contrainteConstraint nullability mismatch

Types Nullable dans un contexte d’annotation désactivéNullable types in disabled annotation context

Incompatibilité de substitution et d’implémentation de la possibilité de valeur nullOverride and implementation nullability mismatch

Attributs pour le comportement de la valeur null spécialeAttributes for special null behavior