C# 8.0 erkennt mehr Programmierfehler

Referenztypen werden nicht mehr automatisch "nullable" sein; die Möglichkeit, den Wert null zuzuweisen, müssen Entwickler explizit deklarieren.

In Pocket speichern vorlesen Druckansicht 18 Kommentare lesen
Lesezeit: 4 Min.
Von
  • Dr. Holger Schwichtenberg
Inhaltsverzeichnis

Bereits im September hatte ich von den Plänen für C# 8.0 berichtet: Referenztypen werden nicht mehr automatisch "nullable" sein; die Möglichkeit, den Wert null zuzuweisen, müssen Entwickler explizit deklarieren.

Noch gibt es C# 8.0 nicht in einer stabilen Version. Da aber Neugier zu meinem Job gehört und ich auf der Community-Konferenz DOTNET Cologne über die neueren Entwicklungen bei C# berichten werde, habe ich mir den Quellcode von GitHub aus dem Entwicklungszweig "features/NullableReferenceTypes" besorgt und den C#-Kommandozeilencompiler csc.exe selbst übersetzt.

Zum Test verwende ich ein etwas erweitertes "Hallo Welt"-Programm. Der aktuelle stabile C#-Compiler (Version 2.8, erschienen am 1. Mai 2018) für die Version 7.3 der Programmiersprache C# übersetzt den Programmcode fehlerfrei und ohne Warnungen.

Einwandfrei funktionieren kann er freilich nicht: Bei der Ausführung sieht man direkt zweimal den Laufzeitfehler: "Object reference not set to an instance of an object."

Hier müsste man Null-Prüfungen (siehe auskommentierte Zeile) oder Null-Werte-Toleranz einbauen, zum Beispiel Console.WriteLine (s?.Trim()).

using System;
namespace CS80Demo {

class Hello {

static string Einleitung = null;

static void Main () {

try {
Print ("Guten Tag!");
Print (Einleitung);
} catch (System.Exception ex) {
Console.WriteLine ("ERROR: " + ex.Message);
}

try {
Person p1 = new Person () { ID = 123, Name = "Holger Schwichtenberg" };
PrintPerson (p1);

Person p2 = null;
PrintPerson (p2);

Print ("... und auf Wiedersehen!");
} catch (System.Exception ex) {
Console.WriteLine ("ERROR: " + ex.Message);
}
}

static void Print (string s) {
Console.WriteLine (s.Trim ());
}

static void PrintPerson (Person p) {
// if (p==null) { Console.WriteLine("Person ist leer!"); return; }
Console.WriteLine (p.ID + ": " + p.Name);
}
}

class Person {
public int ID { get; set; }
public string Name { get; set; }
}
}

Nutzt man für die Übersetzung den C#-8.0-Compiler, erhält man hingegen schon beim Übersetzen entsprechende Warnungen, dass NullReferenceException-Fehler drohen (siehe Screenshot).

In C# 8.0 muss man die oben genannte Null-Prüfung beziehungsweise Null-Toleranz einbauen und zusätzlich das mit dem Fragezeichen hinter den Typen string? und Person? deklarieren, dass hier überhaupt Null-Werte zuweisbar sein sollen.

using System;
namespace CS80Demo {

class Hello {

static string Einleitung = null;

static void Main () {

try {
Print ("Guten Tag!");
Print (Einleitung);
} catch (System.Exception ex) {
Console.WriteLine ("ERROR: " + ex.Message);
}

try {
Person?
p1 = new Person () { ID = 123, Name = "Holger Schwichtenberg" };
PrintPerson (p1);

Person?
p2 = null;
PrintPerson (p2);

Print ("... und auf Wiedersehen!");
} catch (System.Exception ex) {
Console.WriteLine ("ERROR: " + ex.Message);
}
}

static void Print (string? s) {
Console.WriteLine(s?.Trim ());
}

static void PrintPerson (Person? p) {
if (p==null) { Console.WriteLine("Person ist leer!"); return; }
Console.WriteLine (p.ID + ": " + p.Name);
}
}

class Person {
public int ID { get; set; }
public string? Name { get; set; }
}
}

Das ist natürlich ein "Breaking Change", der aber gemäß Semantic Versioning zwischen C# 7.x und C# 8.0 erlaubt wäre. Microsoft hat für solche Breaking Changes bereits vorgesorgt: Seit Visual Studio 2017 Update 3 (Version 15.3) können Entwickler in jedem Projekt die C#-Sprachversion in den Projekteigenschaften (Build | Advanced) einstellen – unabhängig von der verwendeten .NET- und Visual-Studio-Version. C# 8.0 kann man aber in Visual Studio 2017 Update 7 (v15.7, siehe Screenshot) noch nicht einstellen. Aktuell kann man den C#-8.0-Compiler nur an der Kommandozeile nutzen.

()