> ## Documentation Index
> Fetch the complete documentation index at: https://homelab.amylify.de/llms.txt
> Use this file to discover all available pages before exploring further.

# 4.2.6 Objektorientierung

> Klassen, Objekte, Properties, Konstruktoren, Vererbung, Interfaces, Records und Enums in C#.

Bei der **objektorientierten Programmierung (OOP)** bildest du Dinge der echten Welt als **Objekte** nach. Ein Objekt bündelt **Daten** (was es hat) und **Verhalten** (was es kann).

> [!NOTE]
>
> Eine **Klasse** ist der Bauplan, ein **Objekt** ist ein konkretes Exemplar davon. Aus der Klasse `Hund` entstehen die Objekte `bello` und `rex`.

***

## Klassen und Objekte

```csharp theme={"dark"}
class Hund
{
    // Eigenschaften (Daten)
    public string Name { get; set; }
    public int Alter { get; set; }

    // Konstruktor
    public Hund(string name, int alter)
    {
        Name = name;
        Alter = alter;
    }

    // Methode (Verhalten)
    public void Belle()
    {
        Console.WriteLine($"{Name} sagt: Wuff!");
    }
}

Hund bello = new Hund("Bello", 3);   // Objekt erzeugen
bello.Belle();                        // Bello sagt: Wuff!
bello.Alter = 4;                      // Property ändern
```

> [!NOTE]
>
> In Dateien mit Top-Level-Anweisungen müssen Klassen **unter** dem Hauptcode stehen, oder besser in einer eigenen Datei, zum Beispiel `Hund.cs`.

| Begriff | Bedeutung |
| :- | :- |
| **Feld** | Variable innerhalb einer Klasse |
| **Property** | Kontrollierter Zugriff auf ein Feld mit `get` und `set` |
| **Konstruktor** | Spezielle Methode, die ein Objekt erzeugt. Heißt wie die Klasse |
| **Methode** | Funktion, die zur Klasse gehört |
| **Instanz** | Ein einzelnes Objekt einer Klasse |
| `this` | Verweis auf das aktuelle Objekt |

***

## Zugriffsmodifizierer

Sie steuern, wer auf ein Mitglied zugreifen darf:

| Modifizierer | Zugriff |
| :- | :- |
| `public` | Von überall |
| `private` | Nur innerhalb der eigenen Klasse (Standard bei Klassenmitgliedern) |
| `protected` | Eigene Klasse und abgeleitete Klassen |
| `internal` | Innerhalb desselben Projekts |

> [!TIP]
>
> Grundregel der **Kapselung**: Daten möglichst `private` halten und nur über Properties und Methoden freigeben. So kann die Klasse prüfen, ob ein Wert sinnvoll ist.

***

## Properties

```csharp theme={"dark"}
class Konto
{
    private decimal _kontostand;                 // privates Feld

    public decimal Kontostand => _kontostand;    // nur lesbar von außen

    public string Inhaber { get; init; } = "";   // nur beim Erzeugen setzbar

    public void Einzahlen(decimal betrag)
    {
        if (betrag <= 0)
            throw new ArgumentException("Betrag muss positiv sein.");

        _kontostand += betrag;
    }
}
```

| Schreibweise | Bedeutung |
| :- | :- |
| `{ get; set; }` | Lesen und Schreiben |
| `{ get; }` | Nur lesen, Wert wird im Konstruktor gesetzt |
| `{ get; init; }` | Schreiben nur bei der Erzeugung |
| `=> ausdruck` | Berechnete Property ohne eigenen Speicher |
| `required` | Muss beim Erzeugen angegeben werden |

### Objektinitialisierer

```csharp theme={"dark"}
var konto = new Konto { Inhaber = "Mira" };
```

### Primärer Konstruktor

Kurzform, bei der die Parameter direkt hinter dem Klassennamen stehen:

```csharp theme={"dark"}
class Punkt(int x, int y)
{
    public int X { get; } = x;
    public int Y { get; } = y;

    public double Abstand() => Math.Sqrt(X * X + Y * Y);
}
```

> [!NOTE]
>
> Seit C# 14 kann ein Property-Setter mit dem Schlüsselwort `field` auf das automatisch erzeugte Hintergrundfeld zugreifen: `set => field = value.Trim();`. Das ersetzt das eigene private Feld.

***

## Statische Mitglieder

`static` gehört zur **Klasse** selbst, nicht zu einem einzelnen Objekt:

```csharp theme={"dark"}
class Zaehler
{
    public static int Anzahl { get; private set; }

    public Zaehler()
    {
        Anzahl++;
    }
}

new Zaehler();
new Zaehler();
Console.WriteLine(Zaehler.Anzahl);   // 2
```

Bekannte statische Klassen sind `Console` und `Math`, die du nie mit `new` erzeugst.

***

## Vererbung

Eine Klasse kann von einer anderen **erben** und deren Mitglieder übernehmen. Das vermeidet doppelten Code.

```csharp theme={"dark"}
class Tier
{
    public string Name { get; set; } = "";

    public virtual void Laut()
    {
        Console.WriteLine("...");
    }
}

class Katze : Tier
{
    public override void Laut()
    {
        Console.WriteLine($"{Name}: Miau");
    }
}

class Kuh : Tier
{
    public override void Laut()
    {
        Console.WriteLine($"{Name}: Muh");
    }
}
```

```mermaid theme={"dark"}
classDiagram
    class Tier {
        +string Name
        +Laut()
    }
    class Katze {
        +Laut()
    }
    class Kuh {
        +Laut()
    }
    Tier <|-- Katze
    Tier <|-- Kuh
```

| Schlüsselwort | Bedeutung |
| :- | :- |
| `: Basisklasse` | Erbt von dieser Klasse |
| `virtual` | Methode darf in Unterklassen überschrieben werden |
| `override` | Überschreibt eine `virtual`-Methode |
| `base` | Ruft die Version der Basisklasse auf |
| `abstract` | Klasse oder Methode ohne eigene Umsetzung, Unterklassen müssen sie liefern |
| `sealed` | Verhindert weitere Vererbung |

### Polymorphie

Eine Variable vom Typ der Basisklasse kann jedes abgeleitete Objekt halten. Aufgerufen wird die passende Version:

```csharp theme={"dark"}
List<Tier> stall =
[
    new Katze { Name = "Minka" },
    new Kuh { Name = "Berta" }
];

foreach (Tier tier in stall)
{
    tier.Laut();   // Minka: Miau, Berta: Muh
}
```

***

## Interfaces

Ein **Interface** legt fest, **was** eine Klasse können muss, aber nicht **wie**. Eine Klasse darf mehrere Interfaces umsetzen, aber nur von einer Klasse erben.

```csharp theme={"dark"}
interface IBezahlbar
{
    decimal Preis { get; }
    void Bezahlen();
}

class Ticket : IBezahlbar
{
    public decimal Preis => 9.50m;

    public void Bezahlen()
    {
        Console.WriteLine($"{Preis:C} bezahlt.");
    }
}
```

| | Klasse (abstract) | Interface |
| :- | :- | :- |
| Vererbung | Nur eine Basisklasse | Beliebig viele Interfaces |
| Beschreibt | "Ist ein" (`Katze` ist ein `Tier`) | "Kann" (`Ticket` ist bezahlbar) |
| Namenskonvention | `PascalCase` | Beginnt mit `I` |

***

## Records, Structs und Enums

> [tab] record
>
> Ideal für reine Daten. Der Compiler erzeugt Gleichheit, `ToString` und `with` automatisch:
>
> ```csharp theme={"dark"}
> public record Person(string Vorname, string Nachname);
>
> var a = new Person("Mira", "Klein");
> var b = a with { Nachname = "Groß" };   // Kopie mit einer Änderung
>
> Console.WriteLine(a);                                    // Person { Vorname = Mira, Nachname = Klein }
> Console.WriteLine(a == new Person("Mira", "Klein"));     // true, vergleicht Inhalte
> ```

> [tab] struct
>
> Ein **Werttyp** für kleine Datenpakete. Jede Variable hat ihre eigene Kopie:
>
> ```csharp theme={"dark"}
> struct Koordinate
> {
>     public int X;
>     public int Y;
> }
> ```

> [tab] enum
>
> Eine feste Auswahl benannter Konstanten:
>
> ```csharp theme={"dark"}
> enum Wochentag { Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag }
>
> Wochentag heute = Wochentag.Freitag;
>
> if (heute == Wochentag.Freitag)
> {
>     Console.WriteLine("Fast Wochenende");
> }
> ```

### Welche Art von Typ?

| Du brauchst | Nimm |
| :- | :- |
| Komplexes Verhalten, veränderlicher Zustand | `class` |
| Reine Daten mit Wertgleichheit | `record` |
| Kleines, unveränderliches Datenpaket | `struct` |
| Eine feste Auswahl an Optionen | `enum` |
| Einen Vertrag für unabhängige Klassen | `interface` |

***

## Weiter

> [card] [4.2.7 Fehler & Dateien](https://homelab.amylify.de/documentation/code/csharp/fehler-dateien.md)
>
> Mit Fehlern umgehen und Daten dauerhaft speichern.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.