İçeriğe geç / Skip to content / Zum Inhalt

C# Klasse und Objekt: Bauplan und Produkt

Ahmet Balaman

Zuletzt aktualisiert:

4 Min. Lesezeit

.NETC#OOPClassObjectProgramming Fundamentals
C# Klasse und Objekt: Bauplan und Produkt

Beim Lernen von OOP war für mich der Anfang das Schwerste. Im vorherigen Beitrag ging es darum, warum OOP überhaupt nötig ist; jetzt sind die Bausteine dran. Was ist eine Klasse, was ein Objekt, und worin liegt der Unterschied? Alle sagten „Eine Klasse ist ein Bauplan“, aber ich konnte damit wenig anfangen.

Bis es eines Tages beim Kuchenbacken in der Küche Klick machte: Die Klasse ist die Backform, die Objekte sind die Kuchen, die aus dieser Form kommen!

Die Analogie mit der Backform

Stellen Sie sich vor: Sie halten eine herzförmige Backform in der Hand.

  • Form (Klasse): Legt fest, wie der Kuchen aussehen wird. Form und Größe stehen fest.
  • Kuchen (Objekte): Die konkreten Produkte, die aus der Form kommen. Jedes ist ein eigener Kuchen.

Eine Kuchenklasse beschreibt die Felder als Form, und die drei daraus erzeugten Objekte tragen dieselben Felder mit anderen Werten

Die Form können Sie nicht essen, die daraus entstandenen Kuchen schon. Aus derselben Form können Sie beliebig viele Kuchen backen, und jeder ist unabhängig von den anderen.

// This is a Class - The cake mold
public class Cake
{
    public string Flavor { get; set; }
    public string Color { get; set; }
    public int Slices { get; set; }
}

// These are Objects - Cakes from the mold
Cake chocolateCake = new Cake();
chocolateCake.Flavor = "Chocolate";
chocolateCake.Color = "Brown";
chocolateCake.Slices = 8;

Cake bananaCake = new Cake();
bananaCake.Flavor = "Banana";
bananaCake.Color = "Yellow";
bananaCake.Slices = 6;

chocolateCake und bananaCake stammen aus derselben Form (Klasse), sind aber völlig verschiedene Produkte (Objekte). Ein Stück vom einen zu essen wirkt sich nicht auf das andere aus.

Was ist eine Klasse?

Eine Klasse ist eine Vorlage, die festlegt, wie etwas beschaffen ist; Microsofts C#-Referenz zu Klassen beschreibt sie als Referenztyp, der als Blueprint für Objekte dient. Sie enthält:

  • Eigenschaften (Properties): Die Merkmale dieser Sache. Farbe, Größe, Name usw.
  • Methoden: Die Handlungen, die diese Sache ausführen kann. Starten, anhalten, berechnen usw.
public class Car
{
    // Properties - Car's characteristics
    public string Brand { get; set; }
    public string Model { get; set; }
    public string Color { get; set; }
    public int Speed { get; set; }
    public bool IsEngineRunning { get; set; }
    
    // Methods - Car's behaviors
    public void StartEngine()
    {
        IsEngineRunning = true;
        Console.WriteLine($"{Brand} {Model} engine started!");
    }
    
    public void StopEngine()
    {
        IsEngineRunning = false;
        Speed = 0;
        Console.WriteLine($"{Brand} {Model} engine stopped.");
    }
    
    public void Accelerate(int amount)
    {
        if (IsEngineRunning)
        {
            Speed += amount;
            Console.WriteLine($"{Brand} accelerated! Current speed: {Speed} km/h");
        }
        else
        {
            Console.WriteLine("You must start the engine first!");
        }
    }
}

Diese Klasse Car tut für sich genommen nichts. Sie sagt lediglich: „So sieht ein Auto aus.“ Um echte Autos zu erzeugen, müssen wir Instanzen anlegen.

Was ist ein Objekt?

Ein Objekt ist eine konkrete Instanz, die aus einer Klasse erzeugt wurde. Jedes Objekt belegt eigenen Speicher und hält seine eigenen Werte.

// Creating instances (Objects)
Car myCar = new Car();
myCar.Brand = "Toyota";
myCar.Model = "Corolla";
myCar.Color = "White";

Car dadsCar = new Car();
dadsCar.Brand = "Ford";
dadsCar.Model = "Focus";
dadsCar.Color = "Blue";

// Each car operates independently
myCar.StartEngine();
myCar.Accelerate(50);

dadsCar.StartEngine();
dadsCar.Accelerate(30);

// Output:
// Toyota Corolla engine started!
// Toyota accelerated! Current speed: 50 km/h
// Ford Focus engine started!
// Ford accelerated! Current speed: 30 km/h

Wenn mein Auto beschleunigt, wirkt sich das nicht auf Papas Auto aus. Beide stammen aus derselben Klasse „Car“, sind nun aber unabhängige Objekte.

Property und Field: kleiner, aber wichtiger Unterschied

In C# gibt es zwei Begriffe: Field und Property. Anfangs werden sie verwechselt, doch der Unterschied zählt: Microsofts Dokumentation zu Properties definiert eine Property als Member, das von außen wie ein Feld aussieht, intern aber über Accessor-Methoden umgesetzt ist.

public class Student
{
    // Field - Direct variable
    public string name;  // ❌ Not recommended
    
    // Property - Controlled access with Get/Set
    public string Name { get; set; }  // ✅ Preferred
    
    // Property with backing field - Full control
    private int _age;
    public int Age
    {
        get { return _age; }
        set 
        { 
            if (value >= 0 && value <= 150)
                _age = value;
            else
                Console.WriteLine("Invalid age!");
        }
    }
}

Der Vorteil von Properties: Sie können beim Zuweisen oder Auslesen eines Werts prüfen. Im Beispiel oben lassen sich unsinnige Werte wie -5 oder 200 nicht als Alter setzen. Was genau das private vor dem Backing-Field abriegelt, erkläre ich im Beitrag zu Zugriffsmodifizierern.

Methoden: die Fähigkeiten von Objekten

Eine Methode ist eine Handlung, die ein Objekt ausführen kann. Sie kann Parameter entgegennehmen und Werte zurückgeben.

public class Calculator
{
    // Method with parameters
    public int Add(int a, int b)
    {
        return a + b;
    }
    
    // Multiple parameters
    public double Average(double x, double y, double z)
    {
        return (x + y + z) / 3;
    }
    
    // Method without parameters
    public void Greet()
    {
        Console.WriteLine("Hello, calculator is ready!");
    }
    
    // void - Returns nothing
    public void PrintResult(int result)
    {
        Console.WriteLine($"Result: {result}");
    }
}

// Usage
Calculator calc = new Calculator();
calc.Greet();

int sum = calc.Add(5, 3);
calc.PrintResult(sum);

double avg = calc.Average(80, 90, 70);
Console.WriteLine($"Average: {avg}");

Praxisbeispiel: ein Bibliothekssystem

Fügen wir alles Gelernte zusammen und entwerfen ein einfaches System zur Bibliotheksverwaltung:

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public string ISBN { get; set; }
    public int PageCount { get; set; }
    public bool IsBorrowed { get; set; }
    
    public void DisplayInfo()
    {
        Console.WriteLine($"📖 {Title}");
        Console.WriteLine($"   Author: {Author}");
        Console.WriteLine($"   ISBN: {ISBN}");
        Console.WriteLine($"   Pages: {PageCount}");
        Console.WriteLine($"   Status: {(IsBorrowed ? "Borrowed" : "Available")}");
    }
}

public class Member
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MemberID { get; set; }
    public List<Book> BorrowedBooks { get; set; }
    
    public Member()
    {
        BorrowedBooks = new List<Book>();
    }
    
    public bool BorrowBook(Book book)
    {
        if (!book.IsBorrowed)
        {
            book.IsBorrowed = true;
            BorrowedBooks.Add(book);
            Console.WriteLine($"✅ {FirstName} {LastName} borrowed '{book.Title}'.");
            return true;
        }
        Console.WriteLine($"❌ '{book.Title}' is currently borrowed.");
        return false;
    }
    
    public void ReturnBook(Book book)
    {
        if (BorrowedBooks.Contains(book))
        {
            book.IsBorrowed = false;
            BorrowedBooks.Remove(book);
            Console.WriteLine($"📚 '{book.Title}' has been returned.");
        }
    }
    
    public void ShowBorrowedList()
    {
        Console.WriteLine($"\nBooks borrowed by {FirstName} {LastName}:");
        if (BorrowedBooks.Count == 0)
        {
            Console.WriteLine("   No borrowed books.");
            return;
        }
        foreach (var book in BorrowedBooks)
        {
            Console.WriteLine($"   - {book.Title}");
        }
    }
}

Und nun verwenden wir diese Klassen:

// Create books
Book book1 = new Book
{
    Title = "Crime and Punishment",
    Author = "Fyodor Dostoevsky",
    ISBN = "978-123-456",
    PageCount = 671
};

Book book2 = new Book
{
    Title = "1984",
    Author = "George Orwell",
    ISBN = "978-789-012",
    PageCount = 352
};

// Create members
Member john = new Member
{
    FirstName = "John",
    LastName = "Smith",
    MemberID = "M001"
};

Member emma = new Member
{
    FirstName = "Emma",
    LastName = "Johnson",
    MemberID = "M002"
};

// Operations
book1.DisplayInfo();
Console.WriteLine();

john.BorrowBook(book1);  // John borrows
emma.BorrowBook(book1);  // Emma can't - already borrowed

emma.BorrowBook(book2);  // Emma borrows another book

john.ShowBorrowedList();
emma.ShowBorrowedList();

john.ReturnBook(book1);  // John returns
emma.BorrowBook(book1);  // Now Emma can borrow it

Diese Klassen Book und Member laufen in der Konsole; wollen Sie dieselben Klassen hinter einen Webdienst stellen, setzt der Einstieg in Minimal APIs genau dort an.

Object-Initializer-Syntax

C# bietet eine praktische Syntax, um beim Erzeugen von Objekten schnell Eigenschaften zuzuweisen; alle Regeln dazu stehen in Microsofts Dokumentation zu Objekt- und Collection-Initialisierern:

// Long way
Book book1 = new Book();
book1.Title = "Crime and Punishment";
book1.Author = "Dostoevsky";
book1.PageCount = 671;

// Object Initializer - Short and clean
Book book2 = new Book
{
    Title = "Crime and Punishment",
    Author = "Dostoevsky",
    PageCount = 671
};

// Can even write in one line (for small objects)
Book book3 = new Book { Title = "1984", Author = "Orwell" };

Das Schlüsselwort this

this bedeutet „das aktuelle Objekt“. Besonders nützlich ist es, wenn Parameternamen mit Eigenschaftsnamen übereinstimmen:

public class Player
{
    public string Name { get; set; }
    public int Score { get; set; }
    
    // Parameter name same as property name
    public void SetInfo(string Name, int Score)
    {
        this.Name = Name;   // this.Name = class property
        this.Score = Score; // Name = parameter
    }
    
    // Method chaining with this (Fluent API)
    public Player SetName(string name)
    {
        this.Name = name;
        return this;  // Return self
    }
    
    public Player SetScore(int score)
    {
        this.Score = score;
        return this;
    }
}

// Fluent API usage
Player player = new Player()
    .SetName("Sarah")
    .SetScore(100);

Zusammenfassung: Klasse und Objekt

Klasse Objekt
Bauplan, Vorlage Konkrete Instanz
Belegt keinen Speicher Belegt Speicher
Definition Verwendung
Eine Beliebig viele
Backform Kuchen

Nächster Schritt: der Konstruktor

Die Konzepte Klasse und Objekt haben wir verstanden. Wie Ihnen vielleicht aufgefallen ist, kann es aber mühsam sein, nach dem Erzeugen eines Objekts jede Eigenschaft einzeln zuzuweisen.

Im nächsten Beitrag lernen wir das Konzept des Konstruktors kennen: jene besondere Methode, die beim Erzeugen eines Objekts automatisch läuft und Anfangswerte setzt.

Bis dahin: Schreiben Sie viele Klassen und erzeugen Sie Objekte! Übung ist die beste Lehrmeisterin. 🚀


Dies ist der zweite Beitrag der Reihe „OOP mit C#“. Im vorherigen Beitrag haben wir OOP vorgestellt, im nächsten behandeln wir das Thema Konstruktor.

Häufig gestellte Fragen

Wie viele Objekte kann ich aus einer Klasse erzeugen?

Beliebig viele. Jeder Aufruf von new belegt einen neuen Speicherbereich mit eigenen Property-Werten; wie bei der Backform gibt es eine Form und so viele Kuchen, wie Sie möchten.

Warum sollte ich eine Property statt eines Fields verwenden?

Eine Property lässt Sie beim Lesen und Schreiben eines Werts eingreifen: Sie können validieren, den Setter später privat machen oder einen berechneten Wert liefern, ohne den aufrufenden Code zu brechen. Mit einer Auto-Property ({ get; set; }) entstehen dabei auch keine Zusatzkosten.

Kann ich eine Methode einer Klasse aufrufen, ohne ein Objekt zu erzeugen?

Nur bei Mitgliedern, die als static markiert sind, etwa Math.Max. Für Instanzmethoden müssen Sie zuerst mit new ein Objekt erzeugen, weil diese Methoden mit den Daten genau dieses Objekts arbeiten.

Kommentare