Menu

C# Klasse und Objekt: Felder, Methoden, new und Referenzen

Wie du in C# eine Klasse deklarierst, ihr Felder und Methoden gibst, Objekte mit new erzeugst und was es bedeutet, dass eine Klasse ein Referenztyp ist: geteilte Objekte, null und NullReferenceException, ToString und Objektinitialisierer.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine Klasse ist ein Typ, den du definierst: Sie gruppiert Daten (Felder) mit dem Code, der auf diesen Daten arbeitet (Methoden). Ein Objekt ist eine Instanz einer Klasse, zur Laufzeit mit new erzeugt. Eine Klasse, viele Objekte, jedes mit eigenen Werten.

Eine Klasse deklarieren und Objekte erzeugen

Eine Klassendeklaration listet ihre Member in geschweiften Klammern auf. Felder enthalten die Daten, Methoden das Verhalten. new ClassName() allokiert ein Objekt und gibt dir eine Referenz darauf.

Ausgabe:

Maya: 120.50
Omar: 40
Withdraw 200 succeeded: False

Jedes Objekt hat sein eigenes Owner und Balance. Innerhalb einer Methode bedeutet Balance „der Kontostand des Objekts, auf dem diese Methode aufgerufen wurde“, deshalb ändern maya.Deposit und omar.Deposit verschiedene Zahlen. Dieses implizite Objekt steht als this zur Verfügung, wenn du es benennen musst.

Felder, denen du nichts zuweist, beginnen mit ihrem Standardwert: 0 für Zahlen, false für bool und null für Strings und andere Klassentypen.

Die Member hier sind public, damit Main sie erreicht. Echte Klassen halten Felder meist private und stellen stattdessen Properties bereit; die Regeln stehen auf der Seite zu Zugriffsmodifizierern. Eine Klasse kann auch einen Konstruktor deklarieren, der ihre Felder beim Erzeugen des Objekts setzt; das behandelt die Seite zu Konstruktoren.

Eine Klasse ist ein Referenztyp

Eine Variable eines Klassentyps enthält nicht das Objekt. Sie enthält eine Referenz auf ein Objekt, das auf dem Heap liegt. Eine Zuweisung der Variable kopiert die Referenz, zwei Variablen können also auf dasselbe Objekt zeigen.

Ausgabe:

5
6
True
False

Hier zeigen sich drei Folgen:

  • Eine Änderung des Objekts über second ist über first sichtbar, weil es nur ein Objekt gibt.
  • Ein Objekt an eine Methode zu übergeben übergibt die Referenz. Die Methode kann die Felder des Objekts ändern, und der Aufrufer sieht das. (Dem Parameter innerhalb der Methode ein neues Objekt zuzuweisen wirkt sich nicht auf die Variable des Aufrufers aus; dafür braucht es ref.)
  • == vergleicht bei zwei Klasseninstanzen standardmäßig Referenzen: „ist das dasselbe Objekt?“, nicht „haben die dieselben Werte?“. lookalike hat identische Daten und ist trotzdem ein anderes Objekt.

Wenn du Kopien bei der Zuweisung und Vergleich nach Wert willst, schau dir Structs an, die Werttypen sind, oder Records, die nach Wert vergleichen.

null und NullReferenceException

Eine Referenzvariable kann null enthalten, was „kein Objekt“ bedeutet. Einen Member über null zu verwenden wirft NullReferenceException, die häufigste Laufzeit-Exception in C#-Code.

Ausgabe:

True
no city on file
NullReferenceException: Address was never set
Lisbon

Die Lösung ist fast nie, die Exception abzufangen. Finde heraus, warum die Referenz null ist, und erzeuge das Objekt entweder früher, prüfe vor der Verwendung oder nimm den Null-bedingten Operator ?., der anhält und null liefert, statt zu werfen. ?? liefert dann einen Ersatzwert. Beide Operatoren werden unter Nullable-Typen behandelt.

ToString überschreiben

Jede Klasse erbt von object, das ToString() bereitstellt. Die geerbte Version gibt den vollständigen Namen des Typs zurück (einschließlich seines Namespaces, falls er einen hat), was selten das ist, was du ausgeben willst. Überschreibe sie:

Ausgabe:

Plain
Mug (8.50)
In cart: Mug (8.50)
Total line: Mug (8.50)

Console.WriteLine, String-Interpolation und + mit einem String rufen ToString() für dich auf. Auch der Debugger zeigt es an, eine Überschreibung ist also nützlich, selbst wenn du das Objekt nie selbst ausgibst.

Objektinitialisierer

Ein Objektinitialisierer setzt öffentliche Felder und Properties direkt nach der Konstruktion des Objekts, im selben Ausdruck. Das liest sich besser als eine Liste von Zuweisungen und funktioniert gut innerhalb von Collection-Literalen.

Ausgabe:

A12: 25 (0 extras)
A13: 40 (2 extras)

Zwei Details beim zweiten Ticket. Price = 40m überschreibt die 25m des Feldinitialisierers, weil der Objektinitialisierer läuft, nachdem das Objekt gebaut wurde. Extras = { "Parking", "Poster" } hat kein new: Es ruft Add auf der Liste auf, die das Feld schon enthält, statt sie zu ersetzen.

Ein Objektinitialisierer ist kein Konstruktor. Er kann nur Member setzen, die aus dem aufrufenden Code zugänglich sind, und er kann nicht erzwingen, dass ein Member überhaupt gesetzt wird. Wenn ein Objekt ohne bestimmte Werte ungültig ist, verlange sie in einem Konstruktor.

Partielle Klassen

Das Schlüsselwort partial teilt eine Klasse auf mehrere Dateien auf. Der Compiler fügt die Teile zu einer einzigen Klasse zusammen.

// Invoice.cs
public partial class Invoice
{
    public decimal Subtotal;
    public decimal Total() => Subtotal + Tax();
}

// Invoice.Tax.cs
public partial class Invoice
{
    private decimal Tax() => Subtotal * 0.2m;
}

Jeder Teil muss partial angeben und im selben Namespace und im selben Projekt liegen. Der übliche Einsatz ist generierter Code: WinForms-Designer, Source Generators und manche ORMs schreiben einen Teil und überlassen dir den anderen, sodass ein erneutes Generieren nie deinen Code überschreibt. Eine handgeschriebene Klasse nur aufzuteilen, damit sie kürzer wirkt, versteckt meist eine Klasse, die eigentlich zwei Klassen sein sollte.

Häufige Fehler

  • Ein Objekt verwenden, bevor es erzeugt ist. Ein Feld eines Klassentyps ist null, bis du ihm new ... zuweist. Der erste Member-Zugriff wirft NullReferenceException.
  • Erwarten, dass eine Zuweisung kopiert. var b = a; gibt bei einer Klasse einen zweiten Namen für dasselbe Objekt. Erzeuge ein neues Objekt und kopiere die Werte, wenn du ein unabhängiges brauchst.
  • Objekte mit == vergleichen und einen Vergleich nach Wert erwarten. Bei Klassen vergleicht es Referenzen, außer die Klasse überlädt == (wie string es tut). Vergleiche die relevanten Felder oder überschreibe Equals.
  • Ein Objekt ausgeben und seinen Typnamen bekommen. Überschreibe ToString().
  • Alles public deklarieren. In kleinen Beispielen funktioniert das, aber so kann jeder Code das Objekt in einen ungültigen Zustand bringen, etwa einen negativen Kontostand. Halte Felder privat und ändere sie über Methoden, die die Regeln prüfen.

Häufig gestellte Fragen

Was ist eine Klasse in C#?

Eine Klasse ist ein Typ, den du definierst: eine benannte Gruppe von Daten (Feldern und Properties) und Verhalten (Methoden). class Account { public decimal Balance; public void Deposit(decimal amount) { Balance += amount; } } deklariert eine. Eine Klasse ist ein Bauplan; sie tut nichts, bis du mit new Objekte daraus erzeugst.

Was ist der Unterschied zwischen einer Klasse und einem Objekt in C#?

Die Klasse ist die Definition, einmal im Quellcode geschrieben. Ein Objekt ist eine Instanz davon, zur Laufzeit mit new erzeugt, mit einer eigenen Kopie jedes Instanzfelds. Zweimal new Account() ergibt zwei Objekte derselben Klasse mit unabhängigen Kontoständen.

Wie erzeugt man in C# ein Objekt?

Mit new, gefolgt vom Klassennamen und den Konstruktorargumenten: var account = new Account();. Öffentliche Felder und Properties kannst du im selben Ausdruck mit einem Objektinitialisierer setzen: new Account { Owner = "Maya" }. Die Variable enthält eine Referenz auf das neue Objekt, nicht das Objekt selbst.

Warum bekomme ich in C# eine NullReferenceException?

Du hast einen Member (.Name, .Length, einen Methodenaufruf) über eine Variable verwendet, die null enthält, es gibt also kein Objekt, auf das er wirken könnte. Häufige Ursachen sind ein nie zugewiesenes Feld (Klassenfelder beginnen als null), ein Nachschlagen, das null geliefert hat, oder eine Methode, die bei einem Fehlschlag null zurückgibt. Prüfe mit if (x != null), nimm x?.Name oder sorge dafür, dass das Objekt vor der Verwendung erzeugt wird.

Wie überschreibe ich ToString in C#?

Deklariere public override string ToString() in deiner Klasse und gib den gewünschten Text zurück, zum Beispiel public override string ToString() => $"{Name} ({Price:F2})";. Ohne das geben Console.WriteLine(obj) und die String-Interpolation den Klassennamen aus, denn das liefert object.ToString().

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S