required-Schlüsselwort in C-Sharp einfach erklärt

post-thumb

Die Veröffentlichung von C# 11 mit .NET 7 im November 2022 liegt inzwischen bereits eine Weile zurück. Weil .NET 7 nur mit Standard Term Support (STS) angeboten wird, also Fehlerkorrekturen und Sicherheitsverbesserungen lediglich für 18 Monate erhält, haben jedoch viele Projekte die Version ausgesetzt. Mit .NET 8 kam im November 2023 wieder eine Long Term Support (LTS) Veröffentlichung (drei Jahre Unterstützung), sodass einige neue .NET- und C#-Funktionalitäten für den breiten Einsatz in Anwendungen verfügbar wurden. Eine kleine, allerdings sehr willkommene Neuerung ist das required-Schlüsselwort für C# 11 und höher, das hier kurz präsentiert wird.

Zur Erläuterung dient im Folgenden das einfache Datentransferobjekt Customer mit zwei Eigenschaften:

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Motivation

Funktional gibt es an der Customer-Klasse nichts auszusetzen: Daten können einfach zugewiesen und ausgelesen werden, Serialisierung und Mapping sind mit gängigen Werkzeugen problemlos möglich und falls es notwendig werden sollte, könnten die automatischen Getter und Setter mit Eigenimplementierungen ersetzt werden, ohne Anpassungen an anderen Stellen zu erfordern.

Dennoch kann mehr zur Unterstützung der Entwickler und zur Vermeidung von Fehlern getan werden. Beispielsweise kann die Zuweisung eines Wertes für eine Eigenschaft vergessen werden. Insbesondere wenn der Customer um neue Eigenschaften ergänzt wird, ist es leicht, eine Verwendung der Klasse unbeabsichtigt zu übergehen.

Ein zusätzlicher Effekt tritt ein, wenn die Klasse in einem Nullable-Kontext definiert wird: In einem solchen Kontext darf die Name-Eigenschaft vom Typ string nicht den Wert null annehmen. Eine Limitierung, die bei der Vermeidung der weit verbreiteten NullReferenceException hilft. Weil der Standardwert für Zeichenketten, abrufbar über default(string), jedoch null ist, löst der Compiler in obiger Customer-Klasse eine Meldung aus:

warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Diese Meldung (Nonnullable reference not initialized ) ist ohne weitere Konfiguration eine Warnung und sollte beachtet werden, um die Vorteile eines Nullable-Kontextes in Anspruch nehmen zu können. Die einfache Lösung durch einen Wechsel des Datentyps der Name-Eigenschaft zu string? ist häufig nicht sinnvoll, weil so bei jeder Verwendung zunächst auf null geprüft werden müsste, obwohl der Fehler eher an anderen Code-Stellen zu suchen ist (vorausgesetzt null stellt keinen validen Wert dar). Alternativ könnte die Eigenschaft direkt mit einem gültigen Wert in der Customer-Klasse initialisiert werden:

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "(unknown)";
}

Wie hier direkt ersichtlich ist, gibt es in vielen Konstellationen keinen allgemeingültigen Standardwert. Eine weitere Möglichkeit wäre die Verwendung eines Konstruktors:

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Customer(int id, string name)
    {
        Id = id;
        Name = name;
    }
}

Zwar muss bei der Konstruktor-Variante kein Standardwert festgelegt werden und es kann überdies sichergestellt werden, dass alle Pflichtfelder einen Wert erhalten. Diese Lösung wird allerdings bei größeren Datentransferobjekten sehr umständlich (für Konsumenten und die Customer-Klasse) und ist nicht (oder nicht ohne Weiteres) mit manchen Fremdbibliotheken kompatibel, die Instanzen anlegen müssen.

required als neue Option

Das required-Schlüsselwort ist für solche Fälle eine charmante Lösung:

class Customer
{
    public required int Id { get; set; }
    public required string Name { get; set; }
}

Anmerkung: Zum Zeitpunkt der Artikelveröffentlichung kennt unser Blog-System required noch nicht als Schlüsselwort und gibt es deswegen leider nicht als solches wieder.

Mit required gekennzeichnete Eigenschaften und Felder müssen bei Instanziierung der sie enthaltenden Klasse explizit einen Wert über einen Objektinitialisierer erhalten (es gibt Sonderlösungen für Konstruktoren; hierfür sei auf die Dokumentation verwiesen). Entsprechend kann von der um die required-Schlüsselwörter erweiterte Definition der Customer-Klasse nur noch eine Instanz erstellt werden, wenn per Objektinitialisierer Id und Name einen Wert erhalten:

Customer largestCustomer = new()
{
    Id = 8192,
    Name = "Contoso Ltd",
};

Der zugewiesene Wert darf dem Standardwert (für Referenzdatentypen null) entsprechen, sodass required keine Einschränkung des Datentyps darstellt, aber Entwickler zu bewussten Initialisierungsentscheidungen zwingt. Im Beispiel dürfte demnach der Id-Eigenschaft der Standardwert für Zahlen 0 zugewiesen werden.

Fehlt bei der Objekterstellung eine Wertzuweisung…

Customer largestCustomer = new()
{
    Id = 8192,
};

…akzeptiert der Compiler dies nicht und produziert eine Fehlermeldung:

error CS9035: Required member 'Customer.Name' must be set in the object initializer or attribute constructor.

Auch die Validierung für Nullable-Kontexte wurde um Unterstützung für das required-Schlüsselwort erweitert, sodass so markierte Felder und Eigenschaften ohne Standardinitialisierer definiert werden dürfen, selbst wenn es Referenzdatentypen sind. Für Customer.Name wird also keine Meldung mehr ausgegeben.

Bei der JSON-Deserialisierung mit System.Text.Json wird das required-Schlüsselwort ebenfalls beachtet (Dokumentation ).

Fazit zum required-Schlüssenwort von C#

Mit dem required-Schlüsselwort hat C# eine neue Funktionalität erhalten, die Entwicklern die Arbeit erleichtern und gelegentlich sogar Fehler verhindern kann. Dabei ist die Verwendung simpel und erfordert keine kryptische Syntax. Des Weiteren wird ein größerer Störfaktor beim Einsatz von Nullable-Kontexten ausgeschaltet, sodass diese deutlich seltener als bisher bei neuen Projekten deaktiviert werden dürften.

Insgesamt ist das Schlüsselwort eine gelungene Spracherweiterung, die voraussichtlich insbesondere bei Datentransferobjekten weite Verwendung finden wird.

Lernen Sie uns kennen

Das sind wir

Wir sind ein Software-Unternehmen mit Hauptsitz in Karlsruhe und auf die Umsetzung von Digitalstrategien durch vernetzte Cloud-Anwendungen spezialisiert. Wir sind Microsoft-Partner und erweitern Standard-Anwendungen bei Bedarf – egal ob Modernisierung, Integration, Implementierung von CRM- oder ERP-Systemen, Cloud Security oder Identity- und Access-Management: Wir unterstützen Sie!

Mehr über uns

Der Objektkultur-Newsletter

Mit unserem Newsletter informieren wir Sie stets über die neuesten Blogbeiträge,
Webcasts und weiteren spannenden Themen rund um die Digitalisierung.

Newsletter abonnieren