Vorschau auf C♯ 8.0

Erst vor wenigen Monaten wurde die Version 7.3 für C♯ veröffentlicht. Mittlerweile sind bereits rund 30 neue Sprachfeatures ausgelegt worden, welche für die nächste Vollversion vorgeschlagen wurden. Noch steht kein Releasedatum fest, aber dennoch sollen hier kurz einige der Vorschläge vorgestellt werden.

Nullable Reference Types

C verfügt bereits über Nullable Primitive Types, also die Möglichkeit, primitive Datentypen wie int mit null zu initialisieren, indem man die Variable mit Typ null? deklariert. Nullable Reference Types sind auf den ersten Blick ein sehr ähnliches Konzept, die Idee dahinter ist jedoch eine ganz andere. Während die Option "nullable" es bei den primitiven Typen erlaubt, etwas zu erreichen was ansonsten syntaktisch inkorrekt und nicht kompilierbar wäre, hat es keine Auswirkung auf die Syntax, wenn ein Referenzdatentyp als "nullable" deklariert wird.

 

Das neue Sprachfeature soll dem Programmierer helfen, klarer auszudrücken, welche Referenzvariablen bewusst null sein können, und welche eben nach einer anfänglichen Initialisierung immer nicht null sein sollen. Dies erlaubt es, dass die IDE Warnungen anzeigt, wo z.B. versucht wird, einen als "nullable" markierten Typ ohne Null-Check zu dereferenzieren oder wenn einer nicht-nullable Variable der Wert null zugewiesen wird. Das Feature soll Opt-Out sein, die Warnungen können also wahlweise ausgeschaltet werden.

 

Die Syntax ist ähnlich wie bei den primitiven Typen gelöst, indem dem Datentyp ein "?" angefügt wird, um eine Variable als nullable zu markieren. Zusätzlich kann bei der Dereferenzierung einer nullable-Variable ein "!" angefügt werden, um die Warnung zu unterdrücken, im Sinne von "mir ist bewusst, dass dies Null sein könnte".

 

Zudem wird mittels "Flow Analysis" geprüft, ob durch explizite Null-Checks eine nullable-Variable an Punkten im Code immer noch null sein kann. Wenn nicht, werden bei der Dereferenzierung keine Warnungen mehr angezeigt, weil sichergestellt wurde, dass die Variable nicht null ist.

string firstName = null;   //Warnung
string? middleName = null; //OK

int length = firstName.Length; //OK
length = middleName.Length;    //Warnung
length = middleName!.Length;   //OK

int? nullableLength = middleName?.Length; //OK

//Expliziter Null-Check
if (middleName is null) {
   return 0;
}

return middleName.Length; //OK, kann nicht mehr null sein

Default Interface Methods

Ein Vorschlag umfasst, dass es möglich sein soll, Methoden in Interfaces mit einer Default-Implementation zu versehen. Dies ist parallel bereits möglich, wenn abstrakte Klassen verwendet werden, jedoch mit der Einschränkung, dass nur von einer abstrakten Klasse geerbt werden kann. Fügt man die Möglichkeit hinzu, in Interfaces eine Default-Implementation einzubinden, kann man solches von der implementierenden Klasse unabhängiges Verhalten implementieren, und zwar von mehreren Interfaces gleichzeitig.

Switch-Expressions

Mit C♯ 8 sollen sogenannte switch-Expressions verfügbar sein. Dies bietet die Möglichkeit, dass ein switch-Block einen Wert zurückgibt, und ist somit eine Möglichkeit, die Funktionalität des ternären Operators auf mehr mögliche Fälle auszudehnen.

 

Switch-Expressions verwenden eine im Vergleich zum klassischen Switch-Statement komprimierte Schreibweise, indem das "case" Schlüsselwort ausgelassen wird und mit Lambda-Expressions gearbeitet wird. Das Schlüsselwort "break"wird ebenfalls nicht benötigt, stattdessen werden die einzelnen Fälle mit Kommata getrennt. Es gibt keinen Fall-Through. Das "default" Schlüsselwort kann hier nicht verwendet werden. Anstelle kann der Ausdruck "_" (underline) eingesetzt werden, welcher auf alle möglichen switch-Werte passt und somit im Grunde denselben Effekt wie "default" hat.

 

Während es bei switch-Statements nicht nötig ist, alle möglichen Fälle abzudecken, also quasi für gewisse Fälle einfach nichts zu machen, ist es bei switch-Expressions essenziell, dass alle Fälle abgedeckt werden. Denn wenn ein Fall vorliegt, für welchen kein Rückgabewert für den Ausdruck angegeben wurde, kann die gesamte switch-Expression nicht ausgewertet werden.

int dayIndex = (int) DateTime.Now.DayOfWeek;
string weekDayName = dayIndex switch {
   0 => "Sonntag",
   1 => "Montag",
   2 => "Dienstag",
   3 => "Mittwoch",
   4 => "Donnerstag",
   5 => "Freitag",
   _ => "Samstag"
};