Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Tip
Neu bei nullablen Verweistypen? Lesen Sie zuerst Nullable-Verweistypen. Dieses Tutorial setzt voraus, dass Sie den Unterschied zwischen nicht NULL-fähigen und NULL-fähigen Verweistypen verstehen und wissen, wie der Compiler den Nullzustand nachverfolgt.
Kommen Sie aus einer anderen Sprache? Wenn Sie die Nullable-Typen von Kotlin, strictNullChecks in TypeScript oder die Optionals von Swift verwendet haben, ist Ihnen das zugrunde liegende Konzept sofort vertraut. Die Übung hier geht es um das Ausdrücken von Designabsichten und nicht um das Erlernen der Syntax.
In diesem Tutorial erstellen Sie eine kleine Bibliothek, die die Durchführung einer Umfrage modelliert. Die Daten weisen zwei unterschiedliche Muster auf, die Sie mithilfe von nullable Referenztypen unterscheiden können:
- Eine Umfragefrage muss immer vorhanden sein. Die Liste der Fragen und der Text jeder Frage kann niemals sein
null. - Möglicherweise fehlt eine Antwort auf eine Frage . Die Befragten können ablehnen, einige oder alle Fragen zu beantworten, und das Modell sollte dies explizit machen.
Sie definieren diese Regeln anhand von nicht NULL-fähigen und NULL-fähigen Verweistypen. Der Compiler warnt dann, wenn das Verhalten des Codes nicht mit dem Entwurf übereinstimmt.
In diesem Tutorial lernen Sie:
- Erstellen Sie die Anwendung.
- Erstellen Sie die Umfragefragen.
- Erstellen Sie eine Umfrage mit Fragen.
- Testen Sie die Nicht-Null-Anforderung.
- Erstellen Sie Antworttypen.
- Erstellen Sie Die Befragten.
- Generieren Sie eine Umfrageantwort.
- Erstellen Sie eine Reihe von Umfrageantworten.
- Überprüfen Sie die Umfrageergebnisse.
Drei Klassen modellen die Umfrage:
-
SurveyQuestion: eine Frage. Der Text und der Fragetyp sind erforderlich. -
SurveyRun: die Sammlung von Fragen sowie die Liste der Befragten. -
SurveyResponse: Antworten einer Befragten, die möglicherweise fehlen.
Jeder Typ verwendet nicht nullzulässige Verweistypen für erforderliche Werte und nullzulässige Verweistypen für fehlende Werte.
Voraussetzungen
- Das neueste .NET SDK
- Visual Studio Code Editor
- Das C# DevKit
In diesem Lernprogramm wird davon ausgegangen, dass Sie mit C# und entweder Visual Studio oder der .NET CLI vertraut sind.
Erstellen Sie die Anwendung und aktivieren Sie die nullfähigen Verweistypen
Erstellen Sie eine neue Konsolenanwendung mit dem Namen NullableIntroduction:
dotnet new console -n NullableIntroduction
cd NullableIntroduction
Erstellen der Umfragefragen
Fügen Sie dem Projekt eine neue Datei hinzu SurveyQuestion.cs , und ersetzen Sie den Inhalt durch den folgenden Code. Der Text und der Fragetyp sind nicht nullfähig, sodass der Konstruktor beide initialisieren muss:
namespace NullableIntroduction;
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion(QuestionType typeOfQuestion, string text)
{
public string QuestionText { get; } = text;
public QuestionType TypeOfQuestion { get; } = typeOfQuestion;
}
Die Konstruktorparameter sind nicht nullable Verweistypen, daher warnt der Compiler den Aufrufer, wenn eines der Argumente sein könnte null.
Erstellen einer Umfrage mit Fragen
Fügen Sie als Nächstes eine neue Datei mit dem Namen SurveyRun.cs zum Projekt hinzu, und definieren Sie eine SurveyRun Klasse, die die Liste der Fragen enthält:
namespace NullableIntroduction;
public class SurveyRun
{
private List<SurveyQuestion> surveyQuestions = [];
public void AddQuestion(QuestionType type, string question) =>
AddQuestion(new SurveyQuestion(type, question));
public void AddQuestion(SurveyQuestion surveyQuestion) =>
surveyQuestions.Add(surveyQuestion);
}
Das surveyQuestions-Feld ist ein nicht-nullbarer List<SurveyQuestion>. Es verwendet einen Auflistungsausdruck , um eine leere Liste zu initialisieren. Beide AddQuestion-Überladungen akzeptieren Parameter, die keine Nullwerte zulassen, sodass der Compiler sicherstellt, dass Aufrufer null nicht übergeben.
Erstellen Sie in Program.cs eine SurveyRun und fügen Sie drei Fragen hinzu:
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?");
Testen der Nicht-Null-Anforderung
Um zu sehen, wie der Compiler nicht nullable Parameter erzwingt, versuchen Sie, die folgende Zeile hinzuzufügen und neu zu erstellen:
surveyRun.AddQuestion(QuestionType.Text, default);
Der Compiler gibt die Warnung CS8625 aus, da default für einen Referenztyp zu null ausgewertet wird und AddQuestion ein Nicht-Nullable-string erwartet. Entfernen Sie die Zeile, bevor Sie fortfahren.
Erstellen von Antworttypen
Die Befragten können die Umfrage ablehnen und auch dann, wenn sie teilnehmen, einzelne Fragen überspringen. Beide Formen von „missing“ sind gültige Resultate, und das Typsystem sollte sie sichtbar machen. Sie ausdrücken beide Formen mit null.
Fügen Sie dem Projekt eine neue Datei hinzu SurveyResponse.cs , und definieren Sie eine SurveyResponse Klasse. Verwenden Sie einen primären Konstruktor (Parameter, die für den Typ selbst deklariert sind, verfügbar im gesamten Textkörper), um die immer erforderlichen IdZu erfassen:
namespace NullableIntroduction;
public class SurveyResponse(int id)
{
public int Id { get; } = id;
}
Befragte erstellen
Fügen Sie eine statische Factorymethode hinzu (eine static Methode, die eine neue Instanz des Typs erstellt und zurückgibt, eine Alternative zum direkten Aufrufen des Konstruktors), die Befragten mit einer zufälligen ID erstellt:
private static readonly Random randomGenerator = new Random();
public static SurveyResponse GetRandomId() => new SurveyResponse(randomGenerator.Next());
Generieren einer Umfrageantwort
Fügen Sie als Nächstes die Methode hinzu, die einem Befragten die Umfrage stellt. Speichern Sie die Antworten in einem nullfähigen Wörterbuch, damit der Typ selbst kommuniziert, dass der Antwortende möglicherweise ablehnen kann:
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!";
}
}
Das surveyResponses Feld ist Dictionary<int, string>?. Wenn Sie auf das Feld zugreifen, ohne zuvor auf null zu prüfen, gibt der Compiler eine Warnung aus. Innerhalb von AnswerSurvey verfolgt der Compiler, dass surveyResponses unmittelbar nach dem new-Ausdruck nicht null ist, sodass der Schleifenkörper keine zusätzliche Überprüfung benötigt.
Erstellen einer Reihe von Umfrageantworten
Fügen Sie auf SurveyRun eine Methode hinzu, die eine Liste von Befragten aufbaut, bis genügend Personen der Teilnahme zugestimmt haben:
private List<SurveyResponse>? respondents;
public void PerformSurvey(int numberOfRespondents)
{
int respondentsConsenting = 0;
respondents = [];
while (respondentsConsenting < numberOfRespondents)
{
var respondent = SurveyResponse.GetRandomId();
if (respondent.AnswerSurvey(surveyQuestions))
respondentsConsenting++;
respondents.Add(respondent);
}
}
Das respondents Feld ist List<SurveyResponse>? – es ist null, bis die Umfrage ausgeführt wird.
Rufen Sie PerformSurvey von Main auf:
surveyRun.PerformSurvey(50);
Untersuchen der Umfrageergebnisse
Um Ergebnisse zu melden, stellen Sie einige Hilfsfunktionen aus SurveyResponse und SurveyRun bereit. Fügen Sie SurveyResponseMember mit Ausdruckskörpern hinzu (Member, die mit => und einem einzelnen Ausdruck anstelle eines { ... }-Blocks definiert sind), die das nullbare Wörterbuch verarbeiten:
public bool AnsweredSurvey => surveyResponses != null;
public string Answer(int index) => surveyResponses?.GetValueOrDefault(index) ?? "No answer";
AnsweredSurvey überprüft das Feld anhand von null.
Answer verwendet den ?. Nullbedingungsoperator (der zu null ausgewertet wird, wenn die linke Seite null ist, anstatt eine Ausnahme auszulösen), um sicher zu dereferenzieren, und den ?? Nullzusammenführungsoperator (der den rechten Operanden verwendet, wenn die linke Seite null ist), um einen Nicht-Null-Rückgabewert bereitzustellen. Der Rückgabetyp der Methode ist nicht nullfähig string, sodass Aufrufer keine NULL-Überprüfungen benötigen.
Fügen Sie auf SurveyRun Member mit Ausdruckskörper hinzu, die die Teilnehmerliste und die Fragen verfügbar machen:
public IEnumerable<SurveyResponse> AllParticipants => (respondents ?? Enumerable.Empty<SurveyResponse>());
public ICollection<SurveyQuestion> Questions => surveyQuestions;
public SurveyQuestion GetQuestion(int index) => surveyQuestions[index];
AllParticipants gibt eine nicht-nullbare Sequenz zurück, obwohl respondents möglicherweise null ist. Der ?? Operator ersetzt Enumerable.Empty<SurveyResponse>() , wenn das Feld noch nicht aufgefüllt wird. Wenn Sie die ??-Klausel entfernen, warnt der Compiler, dass die Methode möglicherweise null zurückgibt, obwohl der Rückgabetyp nicht nullbar ist.
Schreiben Sie schließlich den Bericht am Ende von Main:
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");
}
}
Beachten Sie, dass für participant, surveyRun.Questions oder surveyRun.GetQuestion(i) keine Nullprüfung erforderlich ist. Die Typen deklarieren diese Werte als nicht nullable, sodass der Compiler sie in der gesamten Schleife als nicht null behandelt.
Führen Sie die Anwendung aus:
dotnet run
Die Ausgabe ist bei jedem Durchlauf anders, da die Teilnehmenden zufällig generiert werden; jede Zeile gibt jedoch entweder die Antworten eines Teilnehmenden wieder oder vermerkt, dass die Person die Antwort verweigert hat.
Conclusion
Das fertige Beispiel befindet sich im Ordner "csharp/NullableIntroduction " des Repositorys dotnet/samples . Experimentieren Sie durch Ändern der Typen zwischen nullable und nicht-nullable. Das Entfernen eines ? Orts, an dem das Design fehlende Werte zulässt, erzeugt Compilerwarnungen, die auf jeden Ort verweisen, an dem der fehlende Wert wichtig ist.