Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les types référence nullables complètent les types de référence de la même façon que les types valeur nullable complètent les types valeur. Vous déclarez une variable comme un type référence nullable en ajoutant un ?
au type. Par exemple, string?
représente une valeur Nullable string
. Vous pouvez utiliser ces nouveaux types pour exprimer plus clairement votre intention de conception : certaines variables doivent toujours avoir une valeur, d’autres peuvent manquer une valeur.
Dans ce tutoriel, vous apprendrez comment le faire :
- Incorporez des types de références annulables et non annulables dans vos conceptions
- Activez les vérifications de type de référence nullable dans l'ensemble de votre code.
- Écrivez du code dans lequel le compilateur applique ces décisions de conception.
- Utilisez la fonctionnalité de référence nullable dans la conception de vos propres projets
Conditions préalables
- La dernière version du SDK .NET
- Éditeur de code Visual Studio
- Le DevKit C#
Ce tutoriel suppose de connaître C# et .NET, y compris Visual Studio ou l’interface CLI .NET.
Incluez des types de référence nullables dans vos conceptions
Dans ce tutoriel, vous allez créer une bibliothèque qui modélise l’exécution d’une enquête. Le code utilise à la fois les types de référence nullables et les types de référence non nullables pour représenter les concepts réels. Les questions d’enquête ne peuvent jamais être nulles. Un répondant pourrait préférer ne pas répondre à une question. Les réponses peuvent être null
dans ce cas.
Le code que vous allez écrire pour cet exemple exprime cette intention et le compilateur applique cette intention.
Créer l’application et activer des types de référence nullables
Créez une nouvelle application console soit dans Visual Studio, soit en utilisant la ligne de commande avec dotnet new console
. Nommez l’application NullableIntroduction
. Une fois que vous avez créé l’application, vous devez spécifier que l’ensemble du projet se compile dans un contexte d’annotation nullable activé. Ouvrez le fichier .csproj et ajoutez un Nullable
élément à l’élément PropertyGroup
. Affectez-lui la valeur enable
. Vous devez choisir la fonctionnalité des types de référence nullables dans les projets antérieurs à C# 11. Cela est dû au fait qu’une fois la fonctionnalité activée, les déclarations de variables de référence existantes deviennent des types de référence non nullables. Bien que cette décision vous aide à trouver des problèmes où le code existant n’a peut-être pas de vérifications null appropriées, il peut ne pas refléter avec précision votre intention de conception d’origine :
<Nullable>enable</Nullable>
Avant .NET 6, les nouveaux projets n’incluent pas l’élément Nullable
. À compter de .NET 6, les nouveaux projets incluent l’élément <Nullable>enable</Nullable>
dans le fichier projet.
Concevoir les types pour l’application
Cette application d’enquête nécessite la création d’un certain nombre de classes :
- Classe qui modélise la liste des questions.
- Classe qui modélise une liste de personnes contactées pour l’enquête.
- Classe qui modélise les réponses d’une personne qui a effectué l’enquête.
Ces types utilisent des types de référence nullables et non nullables pour exprimer les membres requis et les membres facultatifs. Les types de référence nullables communiquent clairement l'intention de conception.
- Les questions qui font partie de l’enquête ne peuvent jamais être nulles : il n’est pas logique de poser une question vide.
- Les répondants ne peuvent jamais être nuls. Vous voudrez suivre les personnes que vous avez contactés, même les répondants qui ont refusé de participer.
- Toute réponse à une question peut être vide. Les répondants peuvent refuser de répondre à certaines ou toutes les questions.
Si vous avez déjà programmé en C#, vous avez peut-être une telle habitude des types référence qui autorisent les valeurs null
que vous avez raté certaines occasions de déclarer des instances non nullable :
- La collection de questions doit être non Nullable.
- La collection de personnes interrogées doit être non Nullable.
En écrivant le code, vous allez voir qu’utiliser par défaut un type référence non Nullable pour les références permet d’éviter des erreurs courantes susceptibles d’aboutir à des exceptions NullReferenceException. Une leçon de ce tutoriel est que vous avez pris des décisions sur les variables qui pourraient ou ne pouvaient pas être null
. Le langage n’a pas fourni de syntaxe pour exprimer ces décisions. Maintenant, c’est le cas.
L’application que vous allez générer effectue les étapes suivantes :
- Crée une enquête et y ajoute des questions.
- Crée un ensemble pseudo-aléatoire de répondants pour l’enquête.
- Contacte les répondants jusqu'à ce que la taille de l'enquête complète atteigne le nombre cible.
- Écrit des statistiques importantes sur les réponses de l’enquête.
Créer l’enquête avec des types référence nullable et non nullable
Le premier code que vous allez écrire crée l’enquête. Vous allez écrire des classes pour modéliser une question et une enquête. Votre sondage comporte trois types de questions, distingués par le format de la réponse : Oui/Non, réponses numériques et réponses textuelles. Créez une public SurveyQuestion
classe :
namespace NullableIntroduction
{
public class SurveyQuestion
{
}
}
Le compilateur interprète chaque déclaration de variable de type référence comme type de référence non nullable pour le code dans un contexte d’annotation nullable activé. Vous pouvez voir votre premier avertissement en ajoutant des propriétés pour le texte de la question et le type de question, comme indiqué dans le code suivant :
namespace NullableIntroduction
{
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion
{
public string QuestionText { get; }
public QuestionType TypeOfQuestion { get; }
}
}
Comme vous n’avez pas initialisé QuestionText
, le compilateur émet un avertissement indiquant qu’une propriété non nullable n’a pas été initialisée. Votre conception nécessite que le texte de la question soit non nul, donc vous ajoutez un constructeur pour l’initialiser ainsi que la valeur QuestionType
. La définition de classe terminée ressemble au code suivant :
namespace NullableIntroduction;
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion
{
public string QuestionText { get; }
public QuestionType TypeOfQuestion { get; }
public SurveyQuestion(QuestionType typeOfQuestion, string text) =>
(TypeOfQuestion, QuestionText) = (typeOfQuestion, text);
}
L’ajout du constructeur supprime la notification. L’argument du constructeur est également un type de référence non nullable. Le compilateur n’émet donc aucun avertissement.
Ensuite, créez une public
classe nommée SurveyRun
. Cette classe contient une liste d’objets et de SurveyQuestion
méthodes pour ajouter des questions à l’enquête, comme indiqué dans le code suivant :
using System.Collections.Generic;
namespace NullableIntroduction
{
public class SurveyRun
{
private List<SurveyQuestion> surveyQuestions = new List<SurveyQuestion>();
public void AddQuestion(QuestionType type, string question) =>
AddQuestion(new SurveyQuestion(type, question));
public void AddQuestion(SurveyQuestion surveyQuestion) => surveyQuestions.Add(surveyQuestion);
}
}
Comme précédemment, vous devez initialiser l’objet de liste en une valeur non null ou le compilateur émet un avertissement. Il n’existe aucune vérification null dans la deuxième surcharge, AddQuestion
car le compilateur permet d’appliquer le contrat non nullable : vous avez déclaré cette variable comme non nullable. Bien que le compilateur avertisse des potentielles affectations null, les valeurs null pendant l'exécution sont toujours possibles. Pour les API publiques, envisagez d’ajouter une validation d’argument même pour les types de référence non nullables, car le code client n’a peut-être pas activé de types de référence nullables ou peut passer intentionnellement null.
Basculez vers Program.cs dans votre éditeur et remplacez le contenu de Main
par les lignes de code suivantes :
var surveyRun = new SurveyRun();
surveyRun.AddQuestion(QuestionType.YesNo, "Has your code ever thrown a NullReferenceException?");
surveyRun.AddQuestion(new SurveyQuestion(QuestionType.Number, "How many times (to the nearest 100) has that happened?"));
surveyRun.AddQuestion(QuestionType.Text, "What is your favorite color?");
Étant donné que l’ensemble du projet se trouve dans un contexte d’annotation nullable activé, vous recevrez des avertissements lorsque vous passez null
à n’importe quelle méthode qui attend un type de référence non-nullable. Essayez-le en ajoutant la ligne suivante à Main
:
surveyRun.AddQuestion(QuestionType.Text, default);
Créer des répondants et obtenir des réponses à l’enquête
Ensuite, écrivez le code qui génère des réponses à l’enquête. Ce processus implique plusieurs petites tâches :
- Créez une méthode qui génère des objets répondants. Ces personnes représentent les personnes qui ont demandé de remplir l’enquête.
- Créez une logique permettant de simuler la pose des questions à un répondant et de recueillir des réponses ou de noter qu’un répondant n’a pas répondu.
- Répétez jusqu’à ce que suffisamment de répondants aient répondu à l’enquête.
Vous aurez besoin d’une classe pour représenter une réponse d’enquête. Ajoutez-le maintenant. Activez la prise en charge Nullable. Ajoutez une Id
propriété et un constructeur qui l’initialise, comme indiqué dans le code suivant :
namespace NullableIntroduction
{
public class SurveyResponse
{
public int Id { get; }
public SurveyResponse(int id) => Id = id;
}
}
Ensuite, ajoutez une static
méthode pour créer des participants en générant un ID aléatoire :
private static readonly Random randomGenerator = new Random();
public static SurveyResponse GetRandomId() => new SurveyResponse(randomGenerator.Next());
La principale responsabilité de cette classe est de générer les réponses d’un participant aux questions de l’enquête. Cette responsabilité comporte quelques étapes :
- Demandez la participation à l’enquête. Si la personne ne consent pas, retournez une réponse absente (ou nulle).
- Posez chaque question et enregistrez la réponse. Chaque réponse peut également être manquante (ou null).
Ajoutez le code suivant à la classe SurveyResponse
:
private Dictionary<int, string>? surveyResponses;
public bool AnswerSurvey(IEnumerable<SurveyQuestion> questions)
{
if (ConsentToSurvey())
{
surveyResponses = new Dictionary<int, string>();
int index = 0;
foreach (var question in questions)
{
var answer = GenerateAnswer(question);
if (answer != null)
{
surveyResponses.Add(index, answer);
}
index++;
}
}
return surveyResponses != null;
}
private bool ConsentToSurvey() => randomGenerator.Next(0, 2) == 1;
private string? GenerateAnswer(SurveyQuestion question)
{
switch (question.TypeOfQuestion)
{
case QuestionType.YesNo:
int n = randomGenerator.Next(-1, 2);
return (n == -1) ? default : (n == 0) ? "No" : "Yes";
case QuestionType.Number:
n = randomGenerator.Next(-30, 101);
return (n < 0) ? default : n.ToString();
case QuestionType.Text:
default:
switch (randomGenerator.Next(0, 5))
{
case 0:
return default;
case 1:
return "Red";
case 2:
return "Green";
case 3:
return "Blue";
}
return "Red. No, Green. Wait.. Blue... AAARGGGGGHHH!";
}
}
Les réponses à l’enquête sont stockées dans un Dictionary<int, string>?
, qui peut donc être Null. Vous utilisez la nouvelle fonctionnalité de langage pour déclarer votre intention de conception, à la fois au compilateur et à toute personne qui lit votre code ultérieurement. Si vous déréférençez surveyResponses
sans d'abord vérifier la valeur de null
, vous obtiendrez un avertissement du compilateur. Vous n’obtenez pas d’avertissement dans la AnswerSurvey
méthode, car le compilateur peut déterminer que la surveyResponses
variable a été définie sur une valeur non null ci-dessus.
L'utilisation de null
pour les réponses manquantes met en évidence un point clé pour travailler avec des types de référence nullables : votre objectif n’est pas de supprimer toutes les valeurs null
de votre programme. Au lieu de cela, votre objectif est de s’assurer que le code que vous écrivez exprime l’intention de votre conception. Les valeurs manquantes sont un concept nécessaire pour exprimer votre code. La null
valeur est un moyen clair d’exprimer ces valeurs manquantes. La tentative de suppression de toutes les null
valeurs entraîne uniquement la définition d’une autre façon d’exprimer ces valeurs manquantes sans null
.
Ensuite, vous devez écrire la PerformSurvey
méthode dans la SurveyRun
classe. Ajoutez le code suivant dans la SurveyRun
classe :
private List<SurveyResponse>? respondents;
public void PerformSurvey(int numberOfRespondents)
{
int respondentsConsenting = 0;
respondents = new List<SurveyResponse>();
while (respondentsConsenting < numberOfRespondents)
{
var respondent = SurveyResponse.GetRandomId();
if (respondent.AnswerSurvey(surveyQuestions))
respondentsConsenting++;
respondents.Add(respondent);
}
}
Ici encore, votre choix d’une valeur Nullable List<SurveyResponse>?
indique que la réponse peut être null. Cela indique que l’enquête n’a pas encore été donnée aux répondants. Notez que les répondants sont ajoutés jusqu'à ce qu'un nombre suffisant ait donné leur consentement.
La dernière étape pour exécuter l’enquête consiste à ajouter un appel pour effectuer l’enquête à la fin de la Main
méthode :
surveyRun.PerformSurvey(50);
Examiner les réponses d’enquête
La dernière étape consiste à afficher les résultats de l’enquête. Vous allez ajouter du code à de nombreuses classes que vous avez écrites. Ce code illustre l'importance de distinguer les types de référence nullables et non-nullables. Commencez par ajouter les deux membres à corps d'expression suivants à la classe SurveyResponse
:
public bool AnsweredSurvey => surveyResponses != null;
public string Answer(int index) => surveyResponses?.GetValueOrDefault(index) ?? "No answer";
Étant donné qu’il surveyResponses
s’agit d’un type de référence nullable, des vérifications de nullité sont nécessaires avant de le déréférencer. La Answer
méthode retourne une chaîne non nullable. Nous devons donc couvrir le cas d’une réponse manquante à l’aide de l’opérateur de fusion null.
Ensuite, ajoutez ces trois membres expression-bodied à la classe SurveyRun
:
public IEnumerable<SurveyResponse> AllParticipants => (respondents ?? Enumerable.Empty<SurveyResponse>());
public ICollection<SurveyQuestion> Questions => surveyQuestions;
public SurveyQuestion GetQuestion(int index) => surveyQuestions[index];
Le AllParticipants
membre doit tenir compte du fait que la respondents
variable peut être null, mais que la valeur de retour ne peut pas être null. Si vous modifiez cette expression en supprimant le ??
et la séquence vide qui suit, le compilateur vous avertit que la méthode pourrait retourner null
et sa signature de retour retourne un type non-nullable.
Enfin, ajoutez la boucle suivante en bas de la Main
méthode :
foreach (var participant in surveyRun.AllParticipants)
{
Console.WriteLine($"Participant: {participant.Id}:");
if (participant.AnsweredSurvey)
{
for (int i = 0; i < surveyRun.Questions.Count; i++)
{
var answer = participant.Answer(i);
Console.WriteLine($"\t{surveyRun.GetQuestion(i).QuestionText} : {answer}");
}
}
else
{
Console.WriteLine("\tNo responses");
}
}
Vous n’avez pas besoin null
de vérifications dans ce code, car vous avez conçu les interfaces sous-jacentes afin qu’elles retournent tous des types de référence non nullables. L’analyse statique du compilateur permet de s’assurer que ces contrats de conception sont suivis.
Obtenir le code
Vous pouvez obtenir le code du didacticiel terminé à partir de notre référentiel d’exemples dans le dossier csharp/NullableIntroduction .
Expérimentez en modifiant les déclarations de type entre les types de référence nullables et non nullables. Découvrez comment cela génère différents avertissements pour vous assurer que vous ne déréférencez accidentellement pas un null
.
Étapes suivantes
Découvrez comment utiliser le type de référence Nullable lors de l’utilisation d’Entity Framework :