C# OOP

6 Kernkonzepte
Die wichtigsten OOP-Konzepte in C#: class · Vererbung · Polymorphie · Interfaces · abstract · sealed C# ist eine vollständig objektorientierte Sprache. Diese Konzepte sind essenziell für die Entwicklung von robusten, wartbaren und erweiterbaren Anwendungen im .NET-Ökosystem.

Klassen & Objekte – Blaupausen für Objekte

class · new · Konstruktor
// Klasse definieren class Person { public string Name { get; set; } public int Alter { get; set; } public Person(string name, int alter) { Name = name; Alter = alter; } } // Objekt erzeugen Person p = new Person("Anna", 30);

Klassen definieren den Bauplan für Objekte. Sie enthalten Daten (Eigenschaften) und Verhalten (Methoden). Objekte werden mit dem new-Operator erzeugt.

Wichtige Klassen-Konzepte

Konzept Beschreibung Beispiel
Eigenschaften Daten mit Getter/Setter public string Name { get; set; }
Felder Private Daten private int _id;
Konstruktor Initialisiert Objekte public Person(string name) { }
Methoden Verhalten public void Greet() { }
this Referenz auf sich selbst this.Name = name;
Beispiele
class Produkt {
// Auto-implementierte Eigenschaften
public string Name { get; set; }
public decimal Preis { get; set; }
// Read-Only Eigenschaft
public string Beschreibung => $"{Name} (€{Preis})";
// Konstruktor
public Produkt(string name, decimal preis) {
Name = name;
Preis = preis;
}
// Methode
public void Anzeigen() {
Console.WriteLine($"{Name} - {Preis:C}");
}
}
// Verwendung
Produkt p = new Produkt("Laptop", 999.99m);
p.Anzeigen(); // Laptop - 999,99 €
Tipp: Verwenden Sie Auto-implementierte Eigenschaften ({ get; set; }) für einfache Daten. Für komplexe Logik implementieren Sie Getter/Setter manuell.

Vererbung – Basisklassen erweitern

: base · override · virtual
// Basisklasse class Tier { public virtual void Laut() { Console.WriteLine("..."); } } // Abgeleitete Klasse class Hund : Tier { public override void Laut() { Console.WriteLine("Wuff!"); } }

Vererbung ermöglicht es, eine neue Klasse auf Basis einer bestehenden zu definieren. Die abgeleitete Klasse erbt alle Member der Basisklasse und kann diese erweitern oder überschreiben.

Vererbungs-Schlüsselwörter

Schlüsselwort Beschreibung
virtual Kann in abgeleiteten Klassen überschrieben werden
override Überschreibt eine virtuelle Methode
base Zugriff auf Member der Basisklasse
new Versteckt eine Basis-Methode (selten)
abstract Muss überschrieben werden (siehe abstrakte Klassen)
sealed Verhindert weitere Vererbung
Beispiele
class Fahrzeug {
public string Marke { get; set; }
public Fahrzeug(string marke) {
Marke = marke;
}
public virtual void Fahren() {
Console.WriteLine($"{Marke} fährt");
}
}
class Auto : Fahrzeug {
public int Tueren { get; set; }
public Auto(string marke, int tueren) : base(marke) {
Tueren = tueren;
}
public override void Fahren() {
base.Fahren();
Console.WriteLine($"mit {Tueren} Türen");
}
}
// Verwendung
Auto auto = new Auto("Tesla", 4);
auto.Fahren(); // Tesla fährt\nmit 4 Türen
Tipp: Verwenden Sie base im Konstruktor, um den Basis-Konstruktor aufzurufen. Verwenden Sie virtual und override für polymorphes Verhalten.

Polymorphie – Viele Formen eines Typs

virtual · override · is · as
// Polymorphe Verwendung Tier tier = new Hund(); tier.Laut(); // "Wuff!" (nicht "...") // Typ-Prüfung if (tier is Hund) { /* ... */ } Hund hund = tier as Hund;

Polymorphie bedeutet, dass ein Objekt mehrere Typen haben kann. Eine Variable vom Basisklassen-Typ kann ein Objekt einer abgeleiteten Klasse enthalten – das überschriebene Verhalten wird zur Laufzeit aufgerufen.

Beispiele
class Figur {
public virtual double Flaeche() => 0;
}
class Kreis : Figur {
public double Radius { get; set; }
public Kreis(double radius) { Radius = radius; }
public override double Flaeche() => Math.PI * Radius * Radius;
}
class Rechteck : Figur {
public double Breite { get; set; }
public double Hoehe { get; set; }
public Rechteck(double breite, double hoehe) {
Breite = breite;
Hoehe = hoehe;
}
public override double Flaeche() => Breite * Hoehe;
}
// Polymorphe Liste
List<Figur> figuren = new List<Figur> {
new Kreis(5),
new Rechteck(4, 6)
};
foreach (var f in figuren) {
Console.WriteLine($"Fläche: {f.Flaeche():F2}");
}
// Typ-Prüfung mit is
if (f is Kreis kreis) {
Console.WriteLine($"Radius: {kreis.Radius}");
}
Tipp: Verwenden Sie is für Typprüfungen und as für sichere Typumwandlungen (returniert null bei Fehlschlag statt Exception).

Interfaces – Verträge definieren

interface · implementiert
// Interface definieren interface ITier { void Laut(); string Name { get; } } // Klasse implementiert Interface class Hund : ITier { public string Name { get; set; } public void Laut() { Console.WriteLine("Wuff!"); } }

Interfaces definieren einen Vertrag – alle Klassen, die ein Interface implementieren, müssen dessen Member bereitstellen. Sie ermöglichen lose Kopplung und Polymorphie ohne Vererbung.

Beispiele
interface IComparable<T> {
int CompareTo(T other);
}
interface ILogger {
void Log(string message);
void LogError(string message);
}
class ConsoleLogger : ILogger {
public void Log(string message) {
Console.WriteLine($"[INFO] {message}");
}
public void LogError(string message) {
Console.WriteLine($"[ERROR] {message}");
}
}
class FileLogger : ILogger {
private string _path;
public FileLogger(string path) { _path = path; }
public void Log(string message) { /* in Datei schreiben */ }
public void LogError(string message) { /* in Datei schreiben */ }
}
// Dependency Injection mit Interfaces
class Service {
private ILogger _logger;
public Service(ILogger logger) {
_logger = logger;
}
public void DoWork() {
_logger.Log("Arbeit gestartet");
}
}
Tipp: Interfaces sind der Schlüssel für lose Kopplung und Testbarkeit. Verwenden Sie Interfaces für Abhängigkeiten (Dependency Injection) und für polymorphe Sammlungen.

Abstrakte Klassen – Unvollständige Basisklassen

abstract · override · virtual
// Abstrakte Klasse abstract class Form { public abstract double Flaeche(); public void Anzeigen() { Console.WriteLine("Form wird angezeigt"); } } // Konkrete Klasse class Kreis : Form { public override double Flaeche() => Math.PI * Radius * Radius; }

Abstrakte Klassen können nicht instanziiert werden. Sie dienen als Basis für andere Klassen und können abstrakte Methoden enthalten, die in abgeleiteten Klassen implementiert werden müssen.

Beispiele
abstract class Mitarbeiter {
public string Name { get; set; }
public int Personalnummer { get; set; }
public Mitarbeiter(string name, int nummer) {
Name = name;
Personalnummer = nummer;
}
// Abstrakte Methode - muss überschrieben werden
public abstract decimal BerechneGehalt();
// Virtuelle Methode - kann überschrieben werden
public virtual void Anzeigen() {
Console.WriteLine($"{Name} ({Personalnummer})");
}
}
class Festangestellter : Mitarbeiter {
public decimal Grundgehalt { get; set; }
public Festangestellter(string name, int nummer, decimal gehalt)
: base(name, nummer) {
Grundgehalt = gehalt;
}
public override decimal BerechneGehalt() => Grundgehalt;
}
class Freiberufler : Mitarbeiter {
public decimal Stundenlohn { get; set; }
public int Stunden { get; set; }
public Freiberufler(string name, int nummer, decimal stundenlohn)
: base(name, nummer) {
Stundenlohn = stundenlohn;
}
public override decimal BerechneGehalt() => Stundenlohn * Stunden;
}
Tipp: Verwenden Sie abstrakte Klassen, wenn Sie gemeinsame Funktionalität (Code) mit abgeleiteten Klassen teilen möchten. Verwenden Sie Interfaces, wenn Sie nur einen Vertrag definieren möchten.

sealed & static – Versiegeln und statische Member

sealed · static · const
// Sealed Klasse (kann nicht vererbt werden) sealed class Endgültig { } // Statische Klasse (nur statische Member) static class MathHelper { public static int Add(int a, int b) => a + b; }

sealed verhindert, dass eine Klasse vererbt wird. static bedeutet, dass der Member zur Klasse gehört, nicht zu einem Objekt – es wird keine Instanz benötigt.

Beispiele
// Sealed Klasse
sealed class Sicherheitsstufe {
public int Level { get; set; }
public Sicherheitsstufe(int level) { Level = level; }
}
// Statische Klasse (Utils)
static class StringExtensions {
public static bool IsNullOrEmpty(string text) {
return string.IsNullOrEmpty(text);
}
public static string ToTitleCase(string text) {
return text?[0].ToString().ToUpper() + text?[1..];
}
}
// Statische Member in einer normalen Klasse
class Zähler {
private static int _anzahl = 0;
public Zähler() { _anzahl++; }
public static int Anzahl => _anzahl;
}
// const (Kompilierzeit-Konstante)
public const double PI = 3.14159265359;
// Verwendung
Console.WriteLine(StringExtensions.ToTitleCase("hallo welt")); // "Hallo welt"
Console.WriteLine($"Zähler: {Zähler.Anzahl}");
Tipp: Verwenden Sie sealed, um unerwünschte Vererbung zu verhindern. Verwenden Sie static für Hilfsfunktionen, die keinen Zustand benötigen. Verwenden Sie const für Werte, die zur Kompilierzeit bekannt sind.

C# OOP im Überblick

class Blaupause für Objekte
Daten + Verhalten
: Vererbung / Interface
Klasse : Basis, Interface
virtual Kann überschrieben werden
override in abgeleiteten Klassen
abstract Muss überschrieben werden
Keine Instanziierung
interface Vertrag
Lose Kopplung
sealed Keine Vererbung
Versiegelte Klasse

Quick Summary

class
Klasse definieren
:
Vererbung
override
Polymorphie
interface
Vertrag
abstract
Abstrakte Klasse
sealed
Versiegelt
class Hund : Tier { public override void Laut() => Console.WriteLine("Wuff"); } · interface ILogger { void Log(string msg); }