Neu in .NET 7 [6]: Required Members mit C# 11.0

Ein neues Schlüsselwort für Microsofts Programmiersprache C# legt fest, dass Properties oder Felder zwingend gesetzt werden müssen.

Lesezeit: 2 Min.
In Pocket speichern
vorlesen Druckansicht Kommentare lesen 5 Beiträge

(Bild: heise online)

Von
  • Dr. Holger Schwichtenberg

Das neue C# bringt das neue Schlüsselwort required für Fields und Properties. Wenn ein Datenmitglied einer Klasse diesen Zusatz erhält, dann ist zwingend erforderlich, dass dieses Datenmitglied entweder im Konstruktor oder Objekt-Initialisierer vom Nutzer der Klasse gesetzt wird. Ein Konstruktor ist mit [SetsRequiredMembers] annotierbar, was dem Compiler anzeigt, dass er alle erforderlichen Mitglieder belegt.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist Chief Technology Expert bei MAXIMAGO, die Innovations- und Experience-getriebener Softwareentwicklung, u.a. in hochkritischen sicherheitstechnischen Bereichen, anbietet. Zudem ist er Leiter des Expertennetzwerks www.IT-Visions.de, das mit 38 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratung und Schulung bei der Entwicklung sowie dem Betrieb von Software unterstützt.

Der Zusatz required ist erlaubt bei Datenmitgliedern in Klassen, Strukturen und Record-Typen, aber nicht in Schnittstellen.

Die folgende Klasse deklariert ein Field und zwei Properties mit required sowie eine weitere Property ohne diesen Zusatz. Zudem gibt es neben dem parameterlosen Konstruktor zwei weitere Konstruktoren mit Parametern, die beide mit [SetsRequiredMembers] annotiert sind; allerdings setzt einer von beiden alle drei der erforderlichen Mitglieder auf belegt.

Der Code kompiliert auch, wenn [SetsRequiredMembers] gar nicht alle erforderlichen Mitglieder setzt. Es gibt auch keine Warnung! Das heißt: Der Compiler verlässt sich auf die Angabe [SetsRequiredMembers] im Code. Der ursprüngliche Plan, dass der Compiler es validiert, wurde verworfen. Ebenso gab es den Plan, dass man einzelne Mitglieder ein- und ausschließen kann. Auch dies ist Stand C# 11.0 nicht möglich. Zitat Microsoft:

"An earlier version of this proposal had a larger metalanguage around initialization, allowing adding and removing individual required members from a constructor, as well as validation that the constructor was setting all required members. This was deemed too complex for the initial release, and removed. We can look at adding more complex contracts and modifications as a later feature."

public class Consultant
{
 public Consultant() { }
 
 [SetsRequiredMembers]
 public Consultant(int id, string name) => 
   (ID, Name) = (id, name);
 [SetsRequiredMembers]
 public Consultant(int id, string name, DateTime created) => 
   (ID, Name, Created) = (id, name, created);
 
 public required int ID; // Required Field
 public required string Name { get; init; } // Required Property
 public required DateTime Created { get; init; } 
   = DateTime.Now; // Required Property
 
 public string? City { get; set; } // nicht "required"!
}

Diese Klasse ist nun wie folgt instanziierbar:

// 1. Aufruf des Konstruktors mit den drei erforderlichen Angaben
var p1 = new Consultant(1, "Dr. Holger Schwichtenberg",
                        DateTime.Now);

// 2. Aufruf des Konstruktors mit nur zwei der drei Angaben
var p2 = new Consultant(2, "Dr. Joachim Fuchs");

// 3. Aufruf der parameterlosen Initialisierung aller drei
// Angaben im Objekt-Initialisierer
var p3 = new Consultant() { ID = 2, Name = 
  "Dr.habil. Klaus Schmaranz", Created = DateTime.Now  };

Nicht erlaubt ist hingegen:

  • Parameterloser Konstruktor ohne Objekt-Initialisierer:
  • Parameterloser Konstruktor mit unvollständigem Objekt-Initialisierer:

Das Beispiel zeigt auch: Es reicht nicht, dass die Property Created eine Standardwertzuweisung in der Klasse besitzt. Der Aufrufer muss trotzdem Created belegen.

Visual Studio zeigt in den Tooltips deutlich an, wenn es erforderlich ist, ein Mitglied zu setzen:

(rme)