Kurz: Eine Klasse bündelt Daten und Verhalten. Von ihr erzeugst du Objekte mit new.
Teil des Kurses C#
Eine Klasse bündelt Daten und Verhalten. Von ihr erzeugst du Objekte mit new.
var rex = new Hund("Rex", 3);
var mimi = new Hund("Mimi", 5) { Rasse = "Siamkatze" }; // Objekt-Initialisierer
rex.Geburtstag();
Console.WriteLine(rex.Bellen());
Console.WriteLine($"{rex} | {mimi.Rasse} | {rex.Alter}");
class Hund
{
public string Name { get; } // nur lesbar (Eigenschaft)
public int Alter { get; private set; } // von außen nur lesbar
public string Rasse { get; set; } = "unbekannt"; // lesen und schreiben, mit Standardwert
public Hund(string name, int alter) // Konstruktor
{
Name = name;
Alter = alter;
}
public void Geburtstag() => Alter++;
public string Bellen() => $"{Name} sagt: Wuff!";
public override string ToString() => $"Hund[{Name}, {Alter}]";
}Ausgabe:
Rex sagt: Wuff!
Hund[Rex, 4] | Siamkatze | 4Eigenschaften (Properties)
Eigenschaften sehen wie Felder aus, laufen aber über get/set und erlauben Prüfungen:
var k = new Konto("Mia");
k.Einzahlen(100);
k.Einzahlen(50);
Console.WriteLine($"{k.Inhaber}: {k.Stand}");
try { k.Einzahlen(-5); } catch (ArgumentException e) { Console.WriteLine("Fehler: " + e.Message); }
k.Limit = 200;
Console.WriteLine($"{k.Limit} {k.IstImPlus}");
class Konto
{
private decimal _stand; // privates Feld
public string Inhaber { get; }
public decimal Stand => _stand; // berechnet/nur lesbar
public bool IstImPlus => _stand > 0;
public decimal Limit
{
get => _limit;
set => _limit = value >= 0 ? value : throw new ArgumentOutOfRangeException(nameof(value));
}
private decimal _limit;
public Konto(string inhaber) => Inhaber = inhaber;
public void Einzahlen(decimal betrag)
{
if (betrag <= 0) throw new ArgumentException("Betrag muss positiv sein", nameof(betrag));
_stand += betrag;
}
}Ausgabe:
Mia: 150
Fehler: Betrag muss positiv sein (Parameter 'betrag')
200 TrueAuto-Eigenschaften ({ get; set; }) legen das Feld selbst an. init erlaubt Zuweisung nur bei der Erzeugung, required erzwingt sie.
var p = new Person { Name = "Mia", Alter = 17 };
Console.WriteLine($"{p.Name} {p.Alter}");
// p.Name = "Tom"; // Fehler: init-only
class Person
{
public required string Name { get; init; } // Pflicht beim Erzeugen, danach unveränderlich
public int Alter { get; init; }
}Ausgabe:
Mia 17static, this, Konstanten
Console.WriteLine(Mathe.Quadrat(7) + " " + Mathe.Pi);
var a = new Zaehler(); var b = new Zaehler();
Console.WriteLine(Zaehler.Anzahl);
static class Mathe // nur statische Member
{
public const double Pi = 3.14159;
public static int Quadrat(int x) => x * x;
}
class Zaehler
{
public static int Anzahl { get; private set; }
public Zaehler() => Anzahl++;
}Ausgabe:
49 3.14159
2Sichtbarkeit
| Modifikator | Sichtbar für |
|---|---|
public | alle |
private | nur die Klasse (Standard bei Membern) |
protected | Klasse und Unterklassen |
internal | dasselbe Projekt (Assembly) |
protected internal, private protected | Kombinationen |
file | nur diese Datei (C# 11) |
Konstruktoren
Console.WriteLine(new Punkt().ToString() + new Punkt(3).ToString() + new Punkt(3, 4));
Console.WriteLine(new Linie(new Punkt(0, 0), new Punkt(3, 4)).Laenge);
class Punkt
{
public double X { get; }
public double Y { get; }
public Punkt() : this(0, 0) { } // Konstruktoren verketten
public Punkt(double x) : this(x, 0) { }
public Punkt(double x, double y) { X = x; Y = y; }
public override string ToString() => $"({X}|{Y})";
}
// Primärkonstruktor (C# 12)
class Linie(Punkt start, Punkt ende)
{
public double Laenge => Math.Sqrt(Math.Pow(ende.X - start.X, 2) + Math.Pow(ende.Y - start.Y, 2));
}Ausgabe:
(0|0)(3|0)(3|4)
5Finalizer, IDisposable und using
Der Garbage Collector verwaltet den Speicher. Für Ressourcen (Dateien, Verbindungen) implementierst du IDisposable und nutzt using:
using (var r = new Ressource("A"))
{
r.Arbeiten();
}
using var b = new Ressource("B"); // wird am Ende des Blocks geschlossen
b.Arbeiten();
Console.WriteLine("Ende");
class Ressource : IDisposable
{
private readonly string _name;
public Ressource(string name) { _name = name; Console.WriteLine($"öffne {_name}"); }
public void Arbeiten() => Console.WriteLine($"{_name} arbeitet");
public void Dispose() => Console.WriteLine($"schließe {_name}");
}Ausgabe:
öffne A
A arbeitet
schließe A
öffne B
B arbeitet
Ende
schließe BMerke
- Klasse: Felder, Eigenschaften (
get/set/init), Methoden, Konstruktoren private set,initundrequiredsteuern Veränderbarkeitstaticgehört zur Klasse;constist eine Compile-Zeit-Konstante- Konstruktoren lassen sich verketten (
: this(...)); Primärkonstruktoren seit C# 12 IDisposable+usingräumen Ressourcen deterministisch auf
Übungsaufgabe
Schreibe eine Klasse Rechteck mit Eigenschaften Breite und Höhe (Prüfung > 0), einer berechneten Eigenschaft Flaeche und ToString.
Quiz zur Selbstkontrolle
Was bewirkt { get; private set; }?
- Von außen nur lesbar, nur innerhalb der Klasse setzbar (richtig)
- Nur schreibbar
- Unveränderlich nach dem Konstruktor
- Privates Feld
Wofür ist using bei IDisposable?
- Dispose wird automatisch am Blockende aufgerufen (richtig)
- Es importiert Namensräume
- Es erzeugt Objekte
- Es startet Threads
Was macht required bei einer Eigenschaft?
- Sie muss beim Erzeugen des Objekts gesetzt werden (richtig)
- Sie ist privat
- Sie ist statisch
- Sie wird gelöscht
Weiter im Kurs
Zurück: Arrays und Collections
Weiter: Vererbung, Interfaces und Polymorphie
Alle Kapitel: C# im Überblick