CodeGym /Kurse /C# SELF /Abstrakte Methoden und Properties

Abstrakte Methoden und Properties

C# SELF
Level 22, Lektion 2
Verfügbar

1. Abstrakte Methoden

In der letzten Vorlesung haben wir das Fundament gelegt: Wir haben abstrakte Klassen kennengelernt und gesehen, dass sie abstrakte Methoden und Properties enthalten können. Wir haben verstanden, dass das ein "Vertrag" ist, der die abgeleiteten Klassen dazu verpflichtet, ihre eigene Implementierung bereitzustellen.

Jetzt lass uns tiefer einsteigen und uns komplexere und praktischere Szenarien anschauen. In dieser Vorlesung konzentrieren wir uns auf Syntax-Details, darauf, wie Abstraktion in mehrstufigen Hierarchien funktioniert, und wir grenzen klar ab, wann man abstract und wann virtual verwenden sollte.

Eine abstrakte Methode ist wie ein mysteriöses Rezept aus einem alten Kochbuch: "Füge eine geheime Zutat hinzu" – welche, steht nicht da, aber alle nachfolgenden Köche müssen sich etwas einfallen lassen!

Eine abstrakte Methode ist immer in einer abstrakten Klasse

Wenn du versuchst, eine abstrakte Methode in einer normalen (nicht-abstrakten) Klasse zu deklarieren, bekommst du einen Compiler-Fehler. Warum? Weil man eine normale Klasse direkt instanziieren kann – und was passiert, wenn du eine nicht implementierte Methode aufrufst? Nur ein fragender Blick von der IDE.


// Das führt zu einem Compiler-Fehler:
public class WrongClass
{
    public abstract void Oops(); // So geht das nicht!
}

Wenn eine Klasse mindestens eine abstrakte Methode enthält, muss sie mit abstract markiert sein!

Implementierung abstrakter Methoden in abgeleiteten Klassen

Die Implementierung erfolgt mit dem Keyword override. Eine Klasse, die von einer abstrakten Klasse erbt und nicht alle abstrakten Methoden implementiert, muss ebenfalls abstrakt sein (sonst meckert der Compiler).

Wir machen mit unserer App-Idee weiter:

In den vorherigen Vorlesungen haben wir die Klasse Shape (Figur) erstellt, in der wir eine abstrakte Methode zur Flächenberechnung deklariert haben. Jetzt erstellen wir konkrete Figuren:


public class Rectangle : Shape
{
    public double Width { get; }
    public double Height { get; }

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; }

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

Warum sind abstrakte Methoden so wichtig?

Abstrakte Methoden sind dein Weg zu sagen: "Leute, wenn ihr diese Klasse erbt, entscheidet selbst, wie das funktionieren soll!" Das macht die Architektur des Programms klarer, schützt vor versehentlichen Auslassungen und – das Wichtigste – ermöglicht es, Polymorphismus voll auszunutzen.

2. Abstrakte Properties

Was ist eine abstrakte Property

Eine abstrakte Property ist genauso ein Vertrag wie eine abstrakte Methode, nur eben für ein Property (property). Für C# ist das ganz natürlich, weil Properties einer der Hauptwege sind, Daten zu kapseln. Eine abstrakte Property sagt: "Lass die Nachfolger selbst entscheiden, woher (und vielleicht wie) sie den Wert dieses Properties bekommen."

Beispiel:
Wir fügen der Figur das Property Name hinzu – jede abgeleitete Klasse soll es haben, aber jede entscheidet selbst, was sie zurückgibt.


public abstract class Shape
{
    public abstract string Name { get; }

    public abstract double CalculateArea();
}

Jetzt muss jeder Nachfolger dieses Property implementieren:


public class Rectangle : Shape
{
    public double Width { get; }
    public double Height { get; }
    public override string Name => "Rechteck";

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; }
    public override string Name => "Kreis";

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

Besonderheiten der Syntax

Eine abstrakte Property ähnelt einer Interface-Property: Sie wird ohne Implementierungskörper deklariert, aber mit Angabe, ob sie nur einen getter oder auch einen setter hat.


public abstract class Creature
{
    // read-only Property
    public abstract string Species { get; }

    // read-write Property
    public abstract int Age { get; set; }
}

In der implementierenden Klasse kannst du die Logik zum Holen (und ggf. Setzen) des Wertes festlegen.

Wozu braucht man abstrakte Properties?

Eine abstrakte Property ist ein super Tool, wenn du willst, dass jeder Nachfolger selbst entscheidet, wie er den Wert bekommt oder speichert. Das braucht man oft beim Modellieren, in Business-Modellen, View-Models und überall dort, wo die Logik hinter dem Property komplexer ist als nur das Zurückgeben eines Feldes.

Zum Beispiel, wenn bei einer Figur der Name per Formel berechnet wird und bei einer anderen einfach eine Konstante ist, kann man das alles schön "verstecken" hinter einer abstrakten Property.

3. Diagramm: Wie hängen abstrakte Klasse, Methoden und Properties zusammen?

Schau dir dieses Diagramm an, um zu sehen, wie das funktioniert:


┌─────────────┐
│ abstract    │
│   Shape     │
│-------------│
│ +Name: str  │  <-- abstrakte Property
│ +Area(): dbl│  <-- abstrakte Methode
└─────┬───────┘
      │
 ┌────▼────┐      ┌───────┐
 │Rectangle│      │ Circle│
 │........ │ .... │ ......│
 │+Name    │      │+Name  │
 │+Area()  │      │+Area()│
 └─────────┘      └───────┘

So stellen wir EIN Interface für alle Nachfolger der Klasse Shape bereit, aber jeder Nachfolger kann "unter der Haube" machen, was er will.

UML-Diagramm für abstrakte Methode und Property:


┌────────────────────────────┐
│        abstract class      │
│           Animal           │
│────────────────────────────│
│+ Name: string {abstract}   │
│+ MakeSound(): void {abstract}│
└─────────────┬──────────────┘
              │
     ┌────────┴──────────┐
     │                   │
┌────────────┐     ┌─────────────┐
│    Cat     │     │    Dog      │
│────────────│     │─────────────│
│+ Name      │     │+ Name       │
│+ MakeSound()│    │+ MakeSound()│
└────────────┘     └─────────────┘

4. Praktische Szenarien und Nutzen für echte Projekte

Abstrakte Methoden und Properties sind dein Werkzeug, wenn du Klassenhierarchien entwirfst, die sich weiterentwickeln sollen. Sie sind das Fundament für große Business-Anwendungen, mehrschichtige Domänenmodelle, Plugin-Systeme, UI-Frameworks, wo für die Basis der Systeme ein "Gesetz" festgelegt wird, das für alle Nachfolger verpflichtend ist.

In echten Projekten ermöglichen solche "sauberen" Architekturentscheidungen, dass du auch nach Monaten und Jahren neue Entitäten und Funktionen einführen kannst, weil der alte Code schon alle Verhaltensvarianten berücksichtigt.

Die "Warum"-Frage und Rückkehr zum Polymorphismus

Polymorphismus wirkt wie Magie, ist aber eigentlich nur ein Vertrag: "Du kannst eine bestimmte Methode bei allen Objekten der Familie aufrufen und bekommst immer das passende Ergebnis." Abstrakte Methoden und Properties sind der Weg, die ganze Hierarchie auf eine gemeinsame Sprache zu verpflichten, aber ohne eine starre "Default"-Implementierung.

So ein Ansatz wird aktiv in Plugin-Systemen (IDE, Grafikeditoren, CRM-Systeme) genutzt, wenn externe Entwickler ihre Erweiterungen schreiben, aber einen Minimalumfang an Funktionen implementieren müssen, den die Plattform verlangt. Zum Beispiel: Wenn du ein Modul zur Dateiverarbeitung schreibst, kann die Basisklasse eine abstrakte Property FileExtension und eine abstrakte Methode Open() enthalten, damit jedes Plugin Dateien seines Typs korrekt verarbeiten kann.

Unterschiede zwischen abstrakten, virtuellen und normalen Klassenmitgliedern

Eigenschaft Normale Methode/Property virtual abstract
Hat Implementierung Ja Ja Nein
Override-Pflicht Nein Nein (kann überschrieben werden) Ja (muss im Nachfolger)
Direkt aufrufbar Ja Ja Nein
Darf in normaler Klasse sein Ja Ja Nein
Darf als sealed markiert werden Nein Ja Nein

5. Anwendung in unserer Lern-App

Jetzt, wo du neues Wissen hast, lass uns zu unserer Figuren-App zurückkehren und schauen, wie abstrakte Properties und Methoden zusammenarbeiten, um ein flexibles und verständliches System zu schaffen.


// Zum Beispiel im Main-Programm
List<Shape> shapes = new List<Shape>
{
    new Rectangle(4, 5),
    new Circle(2.5)
};

foreach (Shape shape in shapes)
{
    // Dank der abstrakten Property Name und der Methode CalculateArea
    // ist uns der konkrete Typ der Figur egal
    Console.WriteLine($"{shape.Name}, Fläche: {shape.CalculateArea():F2}");
}

Ergebnis:

Rechteck, Fläche: 20.00
Kreis, Fläche: 19.63

Schön: Der Code weiß nicht und es ist ihm egal, was für eine Figur das ist – er ruft einfach die benötigten Properties und Methoden auf, und die .NET CLR kümmert sich um die richtige Implementierung!

6. Häufige Fehler und Besonderheiten bei der Implementierung

Fehler Nr. 1: Abstrakte Methode des Elternteils nicht implementiert.
Wenn in einer abgeleiteten Klasse mindestens eine abstrakte Methode oder Property nicht implementiert ist und die Klasse selbst nicht als abstract markiert ist, lässt der Compiler das Projekt nicht bauen. Das ist ein nützlicher Schutz: Du kannst kein Objekt mit "löchriger" Logik erstellen – zum Beispiel eine Figur ohne CalculateArea()-Methode.

Fehler Nr. 2: Methode als abstract deklariert, aber Klasse nicht.
Auch das wird nicht kompiliert. Wenn du in einer Klasse eine abstract-Methode hinzufügst, muss die Klasse selbst abstrakt sein:


public abstract class Polygon : Shape
{
    // CalculateArea() wird nicht implementiert, Klasse bleibt abstract
}

Fehler Nr. 3: Versuch, eine abstrakte Methode mit virtual zu implementieren.
Eine abstrakte Methode muss mit dem Keyword override implementiert werden, nicht mit virtual. Wenn du aber willst, dass die Implementierung weiter unten in der Hierarchie überschrieben werden kann, kannst du die Methode zuerst überschreiben und dann im Kind als virtual deklarieren:


public override double CalculateArea()
{
    // Standard-Implementierung...
}

In einem tieferen Nachfolger kann diese Methode dann erneut überschrieben werden. Aber sie wieder als abstract zu deklarieren, geht nicht, weil es schon eine Implementierung gibt.

2
Aufgabe
C# SELF, Level 22, Lektion 2
Gesperrt
Deklaration einer abstrakten Klasse und Methode
Deklaration einer abstrakten Klasse und Methode
2
Aufgabe
C# SELF, Level 22, Lektion 2
Gesperrt
Abstrakte Methoden und Eigenschaften
Abstrakte Methoden und Eigenschaften
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION