CodeGym /Kurse /C# SELF /Nullable-Typen für Value Types

Nullable-Typen für Value Types

C# SELF
Level 14 , Lektion 0
Verfügbar

1. Einführung

Stell dir mal folgende Situation vor. Du speicherst Daten über Katzen im Code. Und du willst neben dem Alter der Katze zum Beispiel auch Zustände wie "keine Daten" oder "Alter unbekannt" speichern. Man könnte 0 speichern, aber Null ist ja ein ganz legitimes Alter.

int age = 0; // Alter der Katze. Aber was ist 0? Ein Kätzchen oder "unbekannt"?

Das Problem ist, dass int nur ganze Zahlen annimmt, aber "keine Daten" ist bei Zahlen nicht vorgesehen. Wenn das Alter ein String wäre, könnte man null zuweisen. Aber mit Zahlen klappt das nicht:

int age = null; // Fehler! Du kannst null nicht einer int-Variable zuweisen

Das liegt daran, dass Value Types (structs wie int, double, DateTime, bool) immer irgendwas speichern. Die haben keinen "leeren" Zustand (anders als Reference Types, wo null einfach heißt, dass kein Objekt da ist).

Beispiel aus dem Alltag:
Um das zu umgehen, denken sich Programmierer manchmal "besondere" Werte aus: zum Beispiel -1 oder int.MaxValue für "kein Wert". Aber das ist hässlich, unpraktisch und gefährlich: Man kann echte Werte leicht mit Platzhaltern verwechseln.

2. Nullable-Typ: Ein Typ, der auch "null" kann

Die Idee

Was wäre, wenn man normalen Zahlen (und generell allen Value Types) erlauben würde, nicht nur einen Wert, sondern auch null zu speichern?
In C# geht das mit einer speziellen Wrapper-Klasse Nullable<T>. So eine Klasse kann entweder einen Wert vom Typ T enthalten oder nichts (also null).

Syntax

int? age = null; // Die Variable age kann eine Zahl oder null sein
Deklaration eines Nullable-Typs mit ?

Der C#-Compiler versteht so einen Code eigentlich so:

Nullable<int> age = new Nullable<int>(); // Die Variable age hat keinen Wert

Oder, wenn du explizit einen Wert angeben willst:

Nullable<int> age = new Nullable<int>(42); // age enthält die Zahl 42

Das Fragezeichen macht also aus jedem Value Type seine Nullable-Version:

  • int? (das gleiche wie Nullable<int>)
  • double?
  • DateTime?
  • und alle anderen Structs

Nullable-Wrapper für die beliebtesten Value Types

Normaler Typ Nullable-Typ Beispiel
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

Du kannst das auch länger schreiben, mit dem Wrapper-Klassen-Syntax:


Nullable<int> pages = null;
        
Lange Schreibweise

Aber int? zu schreiben ist kürzer und damit cooler.

3. Wie benutzt man Nullable-Typen?

Zuweisung und Überprüfung

Das Zuweisen von null funktioniert genauso wie bei Reference Types:

Deklaration und Zuweisung

int? temperature = null;
temperature = 25;

Check auf null

Wie findest du raus, ob dein Nullable-Type einen echten Wert hat?

if (temperature != null)
{
    Console.WriteLine($"Temperatur: {temperature}");
}
else
{
    Console.WriteLine("Keine Temperaturdaten");
}

Properties von Nullable-Typen: .HasValue und .Value

Nullable-Typen haben zwei wichtige Properties:

  • .HasValue — gibt true zurück, wenn die Variable was enthält (also nicht null ist).
  • .Value — der eigentliche Wert, falls vorhanden (sonst gibt's eine Exception).
int? temperature = null;
if (temperature.HasValue) //keine Exception!
{
    Console.WriteLine($"Temperatur: {temperature.Value}°C");
}
else
{
    Console.WriteLine("Temperatur unbekannt");
}

Dieser Code läuft: temperature ist nicht null, sondern enthält null intern. Du kannst immer die Property HasValue bei einem Nullable-Typ aufrufen. Aber .Value holen, wenn nix drin ist – schlechte Idee, dann gibt's eine InvalidOperationException. Also immer vorher checken!

Kurzschreibweise beim Ausgeben

Oft reicht es, die Nullable-Variable einfach zu benutzen – C# checkt das dann schon:

int? hours = null;
Console.WriteLine(hours); // gibt nix aus (einfach leer)
hours = 10;
Console.WriteLine(hours); // gibt 10 aus

4. Operationen und Nullable-Typen: Rechnen, Vergleiche, Konvertierungen

Operationen: Was passiert?

Wenn einer der Operanden nullable ist, ist das Ergebnis auch nullable.
Und wenn einer der Operanden null ist, ist das Ergebnis auch null.

int? a = 5;
int? b = null;
int? summe = a + b; // summe == null

int? c = 10;
int? d = 15;
int? gesamt = c + d; // gesamt == 25

Vergleichsoperationen

Du kannst Nullable-Typen mit normalen Zahlen vergleichen:

int? score = null;
if (score > 0) Console.WriteLine("Super Ergebnis!");
else Console.WriteLine("Kein Ergebnis"); // Dieser Zweig läuft

Wenn score null ist, ist die Bedingung score > 0 false.

Explizite und implizite Konvertierung

  • Von normalem Typ zu nullable: automatisch.
  • Von nullable zu normal: nur wenn nicht null (sonst Exception).
int? x = 3;
int y = x.Value; // Ok, wenn x nicht null ist

// Implizit
int? z = y;

5. Nullable und Methoden: Parameter und Rückgabewerte

Nullable-Werte zurückgeben

Wenn eine Methode nicht immer ein Ergebnis liefern kann, nimm Nullable-Typen als Rückgabewert:

// Die Methode sucht einen User nach Login und gibt sein Alter zurück, falls gefunden, sonst null
int? FindUserAge(string login)
{
    // ... hier kommt die Suchlogik
    return null; // falls nicht gefunden
}

Nullable-Parameter

Du kannst Nullable-Werte als Parameter nehmen, um klarzumachen: "kann sein, muss aber nicht".

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("Temperatur unbekannt");
    else
        Console.WriteLine($"Temperatur: {temp} Grad");
}
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION