Zum Hauptinhalt springen

Datentypen

Werttypen und Referenztypen

Es gibt zwei grundlegende Kategorien von Datentypen: Werttypen (Value Types) und Referenztypen (Reference Types). Hier ist eine Erklärung beider Typen auf Deutsch:

  1. Werttypen (Value Types):

    • Werttypen repräsentieren Daten, die direkt im Speicher gespeichert werden.
    • Diese Datentypen speichern den Wert selbst, nicht die Referenz auf ein Objekt.
    • Werttypen werden auf dem Stack gespeichert, was bedeutet, dass sie schneller auf den Speicher zugegriffen werden können.
    • Beispiele für Werttypen sind int, float, char, struct und enum.
  2. Referenztypen (Reference Types):

    • Referenztypen repräsentieren Daten, indem sie auf Objekte im Heap-Speicher verweisen.
    • Sie speichern die Referenz auf ein Objekt, nicht den Wert selbst.
    • Referenztypen werden auf dem Heap-Speicher allokiert, was bedeutet, dass sie mehr Speicherplatz benötigen und langsameren Zugriff auf den Wert ermöglichen.
    • Beispiele für Referenztypen sind Klassen (class), Zeichenketten (string), Arrays und benutzerdefinierte Objekte.

Hier ist ein einfaches Beispiel in C#:

// Werttypen
int zahl1 = 10;
int zahl2 = zahl1; // Hier wird eine Kopie von zahl1 erstellt.

// Referenztypen
string text1 = "Hallo";
string text2 = text1; // Hier wird keine Kopie des Textes erstellt; beide variablen verweisen auf dasselbe Objekt im Speicher.

Es ist wichtig zu beachten, dass bei Werttypen Kopien der Werte erstellt werden, während bei Referenztypen Kopien der Referenzen erstellt werden, was dazu führen kann, dass Änderungen an einer Variable auch andere Variablen beeinflussen, die auf dasselbe Objekt verweisen.

// Werttypen-Beispiel
int zahl1 = 10;
int zahl2 = zahl1; // Hier wird eine Kopie von zahl1 erstellt.

Console.WriteLine("Werttypen:");
Console.WriteLine($"zahl1: {zahl1}, zahl2: {zahl2}");

zahl1 = 20; // Änderung von zahl1 hat keinen Einfluss auf zahl2.

Console.WriteLine($"zahl1 nach Änderung: {zahl1}, zahl2: {zahl2}");
Console.WriteLine();


// Referenztypen-Beispiel
List<int> liste1 = new List<int>() { 1, 2, 3 };
List<int> liste2 = liste1; // Hier wird keine Kopie der Liste erstellt; liste2 verweist auf dieselbe Liste.

Console.WriteLine("Referenztypen:");
Console.Write("liste1: ");
foreach (int item in liste1)
{
Console.Write($"{item} ");
}
Console.WriteLine();

Console.Write("liste2: ");
foreach (int item in liste2)
{
Console.Write($"{item} ");
}
Console.WriteLine();

liste1.Add(4); // Änderung an liste1 wirkt sich auch auf liste2 aus.

Console.Write("liste1 nach Änderung: ");
foreach (int item in liste1)
{
Console.Write($"{item} ");
}
Console.WriteLine();

Console.Write("liste2 nach Änderung: ");
foreach (int item in liste2)
{
Console.Write($"{item} ");
}
Console.WriteLine();

Besonderheit von string als Referenztypen

In C# ist string ein besonderer Fall, der oft als Referenztyp behandelt wird, aber tatsächlich eine Ausnahme darstellt. Ein string wird normalerweise als Referenztyp wahrgenommen, da es sich um eine Klasse (System.String) handelt und auf dem Heap-Speicher gespeichert wird. Das bedeutet, dass eine Variable vom Typ string tatsächlich eine Referenz auf ein string-Objekt darstellt.

string text1 = "Hallo";
string text2 = text1; // Hier wird keine Kopie des Textes erstellt; beide Variablen verweisen auf dasselbe string-Objekt im Speicher.

In diesem Fall zeigen text1 und text2 auf dasselbe string-Objekt "Hallo" im Speicher.

Allerdings gibt es eine wichtige Besonderheit bei string in C#: Es ist unveränderlich (immutable). Das bedeutet, wenn Sie den Inhalt eines string ändern, wird tatsächlich ein neues string-Objekt im Speicher erstellt, und die Variable zeigt dann auf das neue Objekt. Beispielsweise:

string text1 = "Hallo";
string text2 = text1; // Hier wird keine Kopie des Textes erstellt.

text1 = "Hallo, Welt!"; // Ein neues string-Objekt wird erstellt, das "Hallo, Welt!" enthält, und text1 zeigt darauf.

Console.WriteLine(text1); // Ausgabe: "Hallo, Welt!"
Console.WriteLine(text2); // Ausgabe: "Hallo"

Obwohl string also wie ein Referenztyp aussieht, verhält es sich aufgrund seiner Unveränderlichkeit anders als andere Referenztypen. Wenn Sie den Inhalt eines string ändern, wird tatsächlich ein neues Objekt erstellt, anstatt den vorhandenen Wert zu ändern.

Datentypenübersicht

.NET-LaufzeittypC#-AliasCLS-konformWertebereich
Bytebyteja0 ... 255
SBytesbytenein–128 ... 127
Int16shortja–215 … 215 – 1
UInt16ushortnein0 … 65.535
Int32intja–231 … 231 – 1
UInt32uintnein0 ... 232 – 1
Int64longja–263 … 263 – 1
UInt64ulongnein0 … 264 – 1
Singlefloatja1,4 × 10–45 bis 3,4 × 1038
Doubledoubleja5,0 × 10–324 bis 1,7 × 10308
Decimaldecimalja+/–79E27 ohne Dezimalpunktangabe; +/–7.9E–29, falls 28 Stellen hinter dem Dezimalpunkt angegeben werden. Die kleinste darstellbare Zahl beträgt +/–1.0E–29.
CharcharjaUnicode-Zeichen zwischen 0 und 65.535
Stringstringjaca. 231 Unicode-Zeichen
Booleanbooljatrue oder false
ObjectobjectjaEine Variable vom Typ Object kann jeden anderen Datentyp enthalten, ist also universell.

Wertebereiche ausgeben

Console.WriteLine($"double from: {double.MinValue}");
Console.WriteLine($"double from: {double.MaxValue}");

Dezimalzahlen

Alle Zahlen müssen bevor sie in eine Variable geschrieben werden, erst in den Speicher in ein Literal geschrieben werden. Dieser ist für Dezimalzahlen double und für Ganzzahlen int.

Daher kommt es bei der ersten Anweisung zu einem Fehler.

// Fehlerhaft
float value = 0.123456789;
// Korrekt
float value2 = 0.123456789f;

Vererbungsstruktur von Zahlen

Typsuffix

SuffixFließkommatyp
F oder ffloat
D oder ddouble
M oder mdecimal

Wertebereiche ausgeben

Console.WriteLine($"double from: {double.MinValue}");
Console.WriteLine($"double from: {double.MaxValue}");

Digit Seperator

long value = 3_584_354_135_131;

Zeichenketten

char letter = 'D';
string text = "Hello world!";

Implizite Datentyp-Konvertierung

Implizite Datentyp-Konvertierung erfolgt, wenn der zuweisende Typ kleiner ist.

Für bool, string und object gibt es keine implizite Konvertierung.

Beispiel

long value1 = 12000;
// Fehlerhaft
int value2 = value1;
// Korrekt
double value3 = value1;

Explizite Konvertierung

Es können nicht alle Konvertierung mit dem Konvertierungsoperator umgewandelt werden. An manchen Stellen kann dafür die Convert Klasse verwendet werden.

 short number1 = 430;
// Fehlerhaft, liefert 174 da die Zahl nach 8 byte abgeschnitten wird
byte number2 = (byte)number1;
Console.WriteLine(number2);
int value4 = 0;
// Fehlerhaft
//bool bolVal = (bool)value4;
// Korrekt
bool bolVal2 = Convert.ToBoolean(value2);
tipp

Es empfiehlt sich immer die Convert-Klasse zum explizite konvertieren zu verwenden, da es sonst zu versteckten Fehlern kommen kann die schwer zu erkennen sind.

Implizit typisierte Variablen

Mit dem Schlüsselwort var kann Datentyp implizit bestimmt werden. Das bedeutet, dass er automatisch vom Compiler zugewiesen wird.

var valueInteger = 8;
Console.WriteLine($"Dei Variable valueInteger ist vom Typ {valueInteger.GetType()}");
var valueDouble = 8d;
Console.WriteLine($"Dei Variable valueInteger ist vom Typ {valueDouble.GetType()}");
var list = new List<int>();
Console.WriteLine($"Dei Variable list ist vom Typ {list.GetType()}");

Nullable Datentypen

Nullable-Werttypen (auch als "Nullable Types" oder "Nullable Value Types" bezeichnet) sind eine spezielle Art von Werttypen, die die Möglichkeit bieten, auch den Wert null (keinen Wert) zu repräsentieren. Dies ist nützlich, wenn Sie Werttypen verwenden möchten, aber auch die Option benötigen, einen Wert als "nicht vorhanden" darzustellen.

Das Schlüsselwort, um einen Werttyp als nullable zu deklarieren, ist Nullable<T>, wobei T der zugrunde liegende Werttyp ist, den Sie nullable machen möchten. Es gibt auch eine syntaktische Abkürzung für die Verwendung von nullable Werttypen, indem ein ? nach dem zugrunde liegenden Werttyp hinzugefügt wird.

Hier ist ein Beispiel für die Verwendung von nullable Werttypen:

int? nullableZahl = null; // Hier ist nullableZahl null, da int? einen nullable int darstellt.

if (nullableZahl.HasValue)
{
Console.WriteLine($"Wert von nullableZahl: {nullableZahl.Value}");
}
else
{
Console.WriteLine("nullableZahl hat keinen Wert (null).");
}

Datentypen umwandeln mit as und is

  1. is-Operator (Typüberprüfung):

    Der is-Operator wird verwendet, um zu überprüfen, ob ein Objekt eine Instanz eines bestimmten Typs oder einer bestimmten Klasse ist. Wenn die Überprüfung erfolgreich ist, gibt is true zurück, andernfalls false.

    Beispiel:

    object obj = "Hallo, Welt!";
    if (obj is string)
    {
    // Objekt ist eine Zeichenkette
    string text = (string)obj; // Typumwandlung ist erforderlich
    Console.WriteLine(text);
    }
    else
    {
    Console.WriteLine("Objekt ist kein String");
    }
  2. as-Operator (Typumwandlung):

    Der as-Operator wird verwendet, um ein Objekt in einen anderen Typ zu konvertieren, sofern die Konvertierung möglich ist. Wenn die Konvertierung erfolgreich ist, gibt as eine Instanz des Zieltyps zurück, andernfalls null.

    Beispiel:

    object obj = "Hallo, Welt!";
    string text = obj as string; // Konvertiert zu string oder gibt null zurück
    if (text != null)
    {
    // Die Konvertierung war erfolgreich
    Console.WriteLine(text);
    }
    else
    {
    Console.WriteLine("Konvertierung zu string fehlgeschlagen");
    }

Wichtige Punkte:

  • Der is-Operator überprüft den Typ und gibt entweder true oder false zurück, ohne das Objekt selbst zu ändern.

  • Der as-Operator versucht, das Objekt in den angegebenen Typ zu konvertieren. Wenn die Konvertierung fehlschlägt, wird null zurückgegeben.

  • Verwenden Sie den as-Operator, wenn Sie eine sichere Typumwandlung durchführen möchten, ohne eine Ausnahme auszulösen. Es ist nützlich, wenn Sie nicht sicher sind, ob die Konvertierung erfolgreich sein wird.

  • Verwenden Sie den is-Operator, wenn Sie lediglich den Typ überprüfen und anschließend eine explizite Typumwandlung (Casting) durchführen möchten, wenn die Überprüfung erfolgreich ist.

Diese beiden Operatoren sind hilfreiche Werkzeuge bei der Arbeit mit objektorientiertem Code, wenn Sie die Typen von Objekten überprüfen oder sie in andere Typen umwandeln müssen, ohne Fehler zu verursachen.


Kommentare