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.
- Dr. Holger Schwichtenberg
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.
C# 7.3 erkennt die Programmierfehler nicht
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; }
}
}
C# 8.0 ist strenger
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; }
}
}
Einstellen der Compiler-Version
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.