Einführung in Klassen

Verweistypen

Ein Typ, der als class definiert ist, ist ein Referenztyp. Wenn Sie zur Laufzeit eine Variable eines Referenztyps deklarieren, enthält die Variable zunächst den Wert null, bis Sie explizit eine Instanz der Klasse mithilfe des new-Operators erstellen oder ihr ein Objekt zuweisen, das wie im folgenden Beispiel an anderer Stelle erstellt wurde:

//Declaring an object of type MyClass.
MyClass mc = new MyClass();

//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;

Beim Erstellen des Objekts wird im verwalteten Heap für dieses bestimmte Objekt ausreichend Speicherplatz zugewiesen. Die Variable enthält lediglich einen Verweis auf den Speicherort dieses Objekts. Der von einem Objekt verwendete Arbeitsspeicher wird von der automatischen Speicherverwaltungsfunktion der CLR zurückgewonnen, die als Garbage Collection bezeichnet wird. Weitere Informationen zur Garbage Collection finden Sie unter Automatische Speicherverwaltung und Garbage Collection.

Deklarieren von Klassen

Klassen werden mithilfe des Schlüsselworts class gefolgt von einem eindeutigen Bezeichner deklariert, wie im folgenden Beispiel dargestellt:

//[access modifier] - [class] - [identifier]
public class Customer
{
   // Fields, properties, methods and events go here...
}

Ein optionaler Zugriffsmodifizierer wird dem Schlüsselwort class vorangestellt. Der standardmäßige Zugriff für einen class-Typ ist internal. Jeder kann Instanzen dieser Klasse erstellen, da in diesem Fall public verwendet wird. Der Name der Klasse folgt dem class-Schlüsselwort. Der Name der Klasse muss ein gültiger C#-Bezeichnername sein. Der Rest der Definition ist der Text einer Klasse, in dem das Verhalten und die Daten definiert sind. Felder, Eigenschaften, Methoden und Ereignisse für eine Klasse werden zusammen als Klassenmember bezeichnet.

Erstellen von Objekten

Obwohl sie manchmal synonym verwendet werden, sind eine Klasse und ein Objekt unterschiedliche Dinge. Eine Klasse definiert einen Objekttyp, ist aber selbst kein Objekt. Ein Objekt ist eine konkrete Entität, basierend auf einer Klasse, und wird manchmal als Instanz einer Klasse bezeichnet.

Objekte können wie im folgenden Beispiel gezeigt mithilfe des Schlüsselworts new erstellt werden, gefolgt vom Namen der Klasse:

Customer object1 = new Customer();

Wenn eine Instanz einer Klasse erstellt wird, wird ein Verweis auf das Objekt an den Programmierer übergeben. Im vorherigen Beispiel ist object1 ein Verweis auf ein Objekt, das auf Customer basiert. Dieser Verweis bezieht sich auf das neue Objekt, enthält jedoch nicht die Objektdaten selbst. In der Tat können Sie einen Objektverweis erstellen, ohne ein Objekt zu erstellen:

Customer object2;

Es wird nicht empfohlen, einen Objektverweis zu erstellen, der auf kein Objekt verweist. Der Versuch, auf ein Objekt über solch einen Verweis zuzugreifen, schlägt zur Laufzeit fehl. Eine Referenz kann auf ein Objekt verweisen, indem entweder ein neues Objekt erstellt wird oder indem es einem vorhandenen Objekt zugewiesen wird, z. B.:

Customer object3 = new Customer();
Customer object4 = object3;

Dieser Code erstellt zwei Objektverweise, die beide auf dasselbe Objekt verweisen. Aus diesem Grund werden alle Änderungen am Objekt, die über object3 getätigt worden sind, bei nachfolgenden Verwendungen von object4 berücksichtigt. Da auf Objekte, die auf Klassen basieren, durch Verweise zurückgegriffen werden, sind Klassen als Verweistypen bekannt.

Konstruktoren und Initialisierung

In den vorherigen Abschnitten wurde die Syntax zum Deklarieren eines Klassentyps und zum Erstellen einer Instanz dieses Typs vorgestellt. Wenn Sie eine Instanz eines Typs erstellen, sollten Sie sicherstellen, dass ihre Felder und Eigenschaften mit sinnvollen Werten initialisiert werden. Es gibt mehrere Möglichkeiten, die Werte zu initialisieren:

  • Akzeptieren von Standardwerten
  • Feldinitialisierer
  • Konstruktorparameter
  • Objektinitialisierer

Jeder .NET-Typ besitzt einen Standardwert. In der Regel ist dieser Wert für Zahlentypen 0 und für alle Verweistypen null. Sie können diesen Standardwert verwenden, wenn er in Ihrer App angemessen ist.

Wenn der .NET-Standardwert nicht der richtige Wert ist, können Sie einen Anfangswert mithilfe eines Feldinitialisierers festlegen:

public class Container
{
    // Initialize capacity field to a default value of 10:
    private int _capacity = 10;
}

Sie können von Aufrufern verlangen, dass sie einen Anfangswert bereitstellen, indem Sie einen Konstruktor definieren, der für das Festlegen dieses Anfangswerts zuständig ist:

public class Container
{
    private int _capacity;

    public Container(int capacity) => _capacity = capacity;
}

Ab C# 12 können Sie einen primären Konstruktor als Teil der Klassendeklaration definieren:

public class Container(int capacity)
{
    private int _capacity = capacity;
}

Das Hinzufügen von Parametern zum Klassennamen definiert den primären Konstruktor. Diese Parameter sind im Klassentext verfügbar, der seine Member enthält. Sie können sie verwenden, um Felder oder Elemente überall dort zu initialisieren, wo sie benötigt werden.

Sie können auch den required-Modifizierer für eine Eigenschaft verwenden und Aufrufern erlauben, einen Objektinitialisierer zu verwenden, um den Anfangswert der Eigenschaft festzulegen:

public class Person
{
    public required string LastName { get; set; }
    public required string FirstName { get; set; }
}

Das Hinzufügen des Schlüsselworts required verlangt, dass Aufrufer diese Eigenschaften als Teil eines new-Ausdrucks zwingend festlegen müssen:

var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };

Klassenvererbung

Klassen unterstützen die Vererbung vollständig. Dies ist ein wesentliches Merkmal der objektorientierten Programmierung. Beim Erstellen einer Klasse können Sie von jeder anderen Klasse erben, die nicht als sealed definiert ist. Andere Klassen können von Ihrer Klasse erben und virtuelle Methoden der Klasse überschreiben. Außerdem kann eine Struktur eine oder mehrere Schnittstellen implementieren.

Die Vererbung erfolgt durch Verwendung einer Ableitung, d.h., dass eine Klasse mithilfe einer Basisklasse deklariert wird, aus der Sie Daten und das Verhalten erbt. Eine Basisklasse wird durch Anhängen eines Doppelpunkts sowie den Namen der Basisklasse angegeben, die dem abgeleiteten Klassennamen folgt, z.B.:

public class Manager : Employee
{
    // Employee fields, properties, methods and events are inherited
    // New Manager fields, properties, methods and events go here...
}

Wenn eine Klassendeklaration eine Basisklasse deklariert, erbt sie alle Member der Basisklasse mit Ausnahme der Konstruktoren. Weitere Informationen finden Sie unter Vererbung.

In C# kann eine Klasse nur direkt von einer Basisklasse erben. Da jedoch eine Basisklasse von einer anderen Klasse erben kann, kann eine Klasse indirekt von mehreren Basisklassen erben. Darüber hinaus kann eine Klasse mehr als eine Schnittstelle direkt implementieren. Weitere Informationen finden Sie unter Schnittstellen.

Eine Klasse kann als abstract deklariert werden. Eine abstrakte Klasse enthält abstrakte Methoden, die über eine Signaturdefinition, aber keine Implementierung verfügen. Abstrakte Klassen können nicht instanziiert werden. Sie können nur mithilfe von abgeleiteten Klassen verwendet werden, die die abstrakten Methoden implementieren. Im Gegensatz dazu lässt eine versiegelte Klasse nicht zu, dass andere Klassen Elemente von ihr ableiten. Weitere Informationen finden Sie unter Abstrakte und versiegelte Klassen und Klassenmember.

Klassendefinitionen können zwischen verschiedenen Quelldateien aufgeteilt werden. Weitere Informationen finden Sie unter Partielle Klassen und Methoden.

C#-Programmiersprachenspezifikation

Weitere Informationen erhalten Sie unter C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.