Erstellen von Klassenkonstruktoren und Instanziierungsobjekten

Abgeschlossen

Neben Klasseneigenschaften und -methoden umfassen Klassendefinitionen Konstruktoren, die zum Initialisieren neuer Objekte (Klasseninstanzen) verwendet werden.

Klassenkonstruktoren

Ein Klassenkonstruktor ist eine Methode mit demselben Namen wie ihr Typ (Konstruktormethoden verwenden denselben Namen wie die Klasse).

Es gibt zwei Typen von Klassenkonstruktoren:

  • Instanzkonstruktoren. Instanzkonstruktoren werden zum Erstellen und Initialisieren von Instanzfeldvariablen verwendet, wenn ein Objekt erstellt wird.
  • Statische Konstruktoren. Statische Konstruktoren werden verwendet, um statische Daten zu initialisieren oder eine bestimmte Aktion auszuführen, die nur einmal ausgeführt werden muss. Statische Konstruktoren werden automatisch aufgerufen, bevor die erste Instanz erstellt wird oder auf statische Member verwiesen wird.

Klassenkonstruktoren sind standardmäßig Instanzkonstruktoren.

Syntax des Instanzkonstruktors

Ein Instanzkonstruktor wird mit demselben Namen wie die Klasse deklariert und enthält keinen Rückgabetyp. Die Methodensignatur des Konstruktors kann einen optionalen Zugriffsmodifizierer, den Methodennamen und seine Parameterliste enthalten. Die Methodensignaturen eines Konstruktors enthalten keinen Rückgabetyp.

Das folgende Beispiel zeigt einen einfachen Konstruktor für eine Klasse mit dem Namen Person:


public class Person
{
    public Person()
    {
        // Field initialization and constructor logic goes here.

    }

    // Remaining implementation of Person class.
}

Klassen können mehrere Konstruktoren aufweisen. Wenn eine Klasse mehrere Konstruktoren aufweist, nehmen die Konstruktoren in der Regel unterschiedliche Argumente.

Das folgende Beispiel zeigt eine Klasse mit dem Namen Person mit zwei Konstruktoren.


public class Person
{

    public Person()
    {
        // Field initialization and constructor logic goes here.
        string name = "Person One";
        Console.WriteLine($"Person created: {name}");

    }

    public Person(string fName, string lName)
    {
        string name = fName + " " + lName;

        Console.WriteLine($"Person created: {name}");
   }

   // Remaining implementation of Person class.
}

Instanziieren von Objekten mithilfe von Klassenkonstruktoren

Wenn ein Objekt mithilfe des schlüsselworts new instanziiert wird, ruft die .NET-Laufzeit den zugehörigen Instanzkonstruktor in der Klassendefinition auf und weist Speicher für das Objekt zu.

Im folgenden Codeausschnitt definiert die Person-Klasse einen einfachen Instanzkonstruktor. Die Program Klasse enthält eine Main Methode, die den new-Operator verwendet, um eine Instanz von Person namens person1zu erstellen. Die Laufzeit ruft den Person-Konstruktor unmittelbar nach der Zuweisung des Speichers für das neue Objekt auf.


public class Person
{
    public Person()
    {
        // Field initialization and constructor logic goes here.

    }
}

static class Program
{
    // the Main method is the entry point of the program.
    static void Main()
    {
        Person person1 = new Person();
    }
}

Konstruktoren mit und ohne Parameter

Ein Konstruktor, der keine Parameter akzeptiert, wird als parameterloser Konstruktor bezeichnet. Die Laufzeit ruft den parameterlosen Konstruktor auf, wenn ein Objekt mithilfe des new-Operators instanziiert wird und dem Konstruktor keine Argumente bereitgestellt werden.

Anmerkung

Sofern die Klasse nicht statisch ist, erhalten Klassen ohne Konstruktoren einen öffentlichen parameterlosen Konstruktor vom C#-Compiler, um die Klasseninstanziierung zu aktivieren.

Klassen definieren häufig Konstruktoren, die Parameter verwenden. Konstruktoren, die Parameter verwenden, müssen mithilfe des new Operators oder einer Basis-Anweisung aufgerufen werden. Klassen können einen oder mehrere Konstruktoren definieren.

Der folgende Codeausschnitt zeigt eine Klasse mit dem Namen Person mit drei Konstruktoren:


public class Person
{

    public Person()
    {
        // Field initialization and constructor logic goes here.

        Console.WriteLine("An instance of the Person class is being instantiated without name or age parameters.");
    }

    public Person(string name)
    {
        // Field initialization and constructor logic goes here.

        Console.WriteLine($"An instance of the Person class is being instantiated using a name ({name}) parameter.");
    }

    public Person(string name, int age)
    {
        // Field initialization and constructor logic goes here.

        Console.WriteLine($"An instance of the Person class is being instantiated using name ({name}) and age ({age}) parameters.");
    }
}

static class Program
{
    // the Main method is the entry point of the program.
    static void Main()
    {
        Person person1 = new Person();
        Person person2 = new Person("Person Two");
        Person person3 = new Person("Person Three", 30);
    }
}

Klassen ohne Konstruktoren

Wenn eine Klasse keine expliziten Instanzkonstruktoren aufweist, stellt C# einen parameterlosen Konstruktor bereit, mit dem Sie eine Instanz dieser Klasse instanziieren können, wie das folgende Beispiel zeigt:


public class Person
{
    public int age;
    public string name = "unknown";
}

class Example
{
    static void Main()
    {
        var person = new Person();
        Console.WriteLine($"Name: {person.name}, Age: {person.age}");
        // Output:  Name: unknown, Age: 0
    }
}

Dieser Konstruktor initialisiert Instanzfelder und -eigenschaften entsprechend den entsprechenden Initialisierern. Wenn ein Feld oder eine Eigenschaft keinen Initialisierer aufweist, wird der Wert auf den Standardwert des Felds oder des Eigenschaftentyps festgelegt. Wenn Sie mindestens einen Instanzkonstruktor in einer Klasse deklarieren, stellt C# keinen parameterlosen Konstruktor bereit.

Initialisieren von Klassendaten mithilfe von Konstruktorparametern

Die an einen Konstruktor übergebenen Parameter sind lokal für den Konstruktor. Parameter werden häufig verwendet, um die Datenfelder einer Klasse zu initialisieren.

Der folgende Codeausschnitt zeigt eine Klasse mit dem Namen Person mit Konstruktoren, die die felder personName und personAge initialisieren:


public class Person
{
    public string personName;
    public string personAge;

    public Person()
    {
        // Field initialization and constructor logic goes here.
        personName = "unknown";
        personAge = "unknown";
    }

    public Person(string name)
    {
        // Field initialization and constructor logic goes here.
        personName = name;
        personAge = "unknown";
    }

    public Person(string name, int age)
    {
        // Field initialization and constructor logic goes here.
        personName = name;
        personAge = age.ToString();
    }
}

static class Program
{
    // the Main method is the entry point of the program.
    static void Main()
    {
        Person person1 = new Person();
        Person person2 = new Person("Person Two");
        Person person3 = new Person("Person Three", 30);

        Console.WriteLine($"Person 1 Name: {person1.personName} Age: {person1.personAge}");
        Console.WriteLine($"Person 2 Name: {person2.personName} Age: {person2.personAge}");
        Console.WriteLine($"Person 3 Name: {person3.personName} Age: {person3.personAge}");
    }
}

Im vorherigen Beispiel wird die Person-Klasse mit drei Konstruktoren definiert. Der erste Konstruktor initialisiert die Felder personName und personAge zum "unknown". Der zweite Konstruktor initialisiert das personName-Feld auf den Wert, der im parameter name übergeben wird, und das feld personAge in "unknown". Der dritte Konstruktor initialisiert die Felder personName und personAge den Werten, die in den parametern name bzw. age übergeben werden.

Da die Felder öffentlich sind, können sie direkt über die Main-Methode aufgerufen werden. Wenn der Code ausgeführt wird, wird die folgende Ausgabe generiert:


Person 1 Name: unknown Age: unknown
Person 2 Name: Person Two Age: unknown
Person 3 Name: Person Three Age: 30

Ausdruckstextdefinitionen

Wenn ein Konstruktor als einzelne Anweisung implementiert werden kann, können Sie beim Implementieren des Konstruktors eine Ausdruckstextdefinition verwenden, um einem Klassenelement einen Parameter zuzuweisen.

Der folgende Konstruktor initialisiert z. B. das modelName-Feld mit dem wert, der an den parameter model übergeben wird:


public class Car
{
    public string modelName;

    public Car(string model) => modelName = model;
    
}

Die Car Klasse verfügt über ein einzelnes öffentliches Feld, modelName, das vom Typ stringist. Das Feld modelName soll den Namen des Automodells speichern.

Die Car Klasse enthält auch einen Konstruktor, der einen einzelnen Zeichenfolgenparameter mit dem Namen modelverwendet. Der Konstruktor verwendet eine Ausdruckstextdefinition (die durch die => syntax bezeichnet wird), um das modelName-Feld mit dem an den model Parameter übergebenen Wert zu initialisieren. Dies bedeutet, dass beim Instanziieren eines neuen Car-Objekts das feld modelName auf den Wert festgelegt wird, der als Argument für den Konstruktor bereitgestellt wird.

Wie der Begriff Ausdruck impliziert, ist die rechte Seite des =>-Operators ein Ausdruck und ist nicht auf eine einfache Zuordnungsanweisung beschränkt. Der Ausdruck kann ein beliebiger gültiger C#-Ausdruck sein, der einen Wert zurückgibt.

Der folgende Codeausschnitt veranschaulicht, wie eine Ausdruckstextdefinition implementiert wird, die eine einfache Berechnung ausführt:


public class Employee
{
    public int Salary;

    public Employee() { }

    public Employee(int annualSalary) => Salary = annualSalary;

    public Employee(int weeklySalary, int numberOfWeeks) => Salary = weeklySalary * numberOfWeeks;
}

Diese Klasse kann mithilfe einer der folgenden Anweisungen erstellt werden:


Employee e1 = new Employee(30000);
Employee e2 = new Employee(500, 52);

Statische Konstruktoren

Ein statischer Konstruktor wird verwendet, um statische Daten zu initialisieren oder eine bestimmte Aktion auszuführen, die nur einmal ausgeführt werden muss. Sie wird automatisch aufgerufen, bevor die erste Instanz erstellt wird oder auf statische Member verwiesen wird. Ein statischer Konstruktor wird höchstens einmal aufgerufen.

Der folgende Codeausschnitt zeigt eine aktualisierte Version der Person Klasse, die statische Felder und einen statischen Konstruktor implementiert:


public class Person
{
    public string personName;
    public string personAge;

    // Static field
    public static string defaultName;
    public static string defaultAge;

    // Static constructor
    static Person()
    {
        // Static field initialization
        defaultName = "unknown";
        defaultAge = "unknown";
    }

    public Person()
    {
        // Field initialization and constructor logic goes here.
        personName = defaultName;
        personAge = defaultAge;
    }

    public Person(string name)
    {
        // Field initialization and constructor logic goes here.
        personName = name;
        personAge = defaultAge;
    }

    public Person(string name, int age)
    {
        // Field initialization and constructor logic goes here.
        personName = name;
        personAge = age.ToString();
    }
}

Die aktualisierte Person Klasse verfügt über zwei Instanzenfelder, personName und personAge, die beide vom Typ stringsind. Diese Felder speichern den Namen bzw. das Alter einer Person.

Die Klasse definiert auch zwei statische Felder, defaultName und defaultAge, auch vom Typ string. Statische Felder werden von allen Instanzen der Klasse gemeinsam verwendet und werden nur einmal initialisiert. In diesem Fall werden die statischen Felder verwendet, um Standardwerte für die Felder personName und personAge bereitzustellen.

Der statische Konstruktor static Person() ist für die Initialisierung der statischen Felder verantwortlich. Sie legt defaultName auf "unknown" und defaultAge auf "unknown"fest. Der statische Konstruktor wird automatisch aufgerufen, bevor instanzen der Klasse erstellt werden oder auf statische Member zugegriffen wird.

Die Person-Klasse enthält drei Instanzkonstruktoren:

Der parameterlose Konstruktor public Person() initialisiert die felder personName und personAge mit den Werten der statischen Felder defaultName und defaultAge. Wenn beim Erstellen eines Person-Objekts keine Argumente angegeben werden, werden die Standardwerte "unknown" sowohl für den Namen als auch für das Alter verwendet.

Der Konstruktor public Person(string name) verwendet einen einzelnen Parameter, nameund initialisiert das personName Feld mit diesem Wert. Das feld personAge wird mit dem Wert des statischen Felds defaultAgeinitialisiert. Dieser Konstruktor ermöglicht die Erstellung eines Person Objekts mit einem angegebenen Namen bei Verwendung des Standardalters.

Der Konstruktor public Person(string name, int age) akzeptiert zwei Parameter, name und age. Es initialisiert das personName-Feld mit dem Wert des name-Parameters und des personAge-Felds mit der Zeichenfolgendarstellung des Altersparameters. Dieser Konstruktor ermöglicht die Erstellung eines Person-Objekts mit einem angegebenen name und age.

Eigenschaften statischer Konstruktoren

Statische Konstruktoren weisen die folgenden Eigenschaften auf:

  • Ein statischer Konstruktor hat keine Zugriffsmodifizierer oder parameter.

  • Eine Klasse kann nur einen statischen Konstruktor haben.

  • Statische Konstruktoren können nicht geerbt oder überladen werden.

  • Ein statischer Konstruktor kann nicht direkt aufgerufen werden und soll nur von der Common Language Runtime (CLR) aufgerufen werden. Sie wird automatisch aufgerufen.

  • Der Benutzer hat keine Kontrolle darüber, wann der statische Konstruktor im Programm ausgeführt wird.

  • Ein statischer Konstruktor wird automatisch aufgerufen. Sie initialisiert die Klasse, bevor die erste Instanz erstellt wird, oder auf in dieser Klasse deklarierte statische Member (nicht die Basisklassen) werden referenziert. Ein statischer Konstruktor wird vor einem Instanzkonstruktor ausgeführt. Wenn statische Feldvariableninitialisierer in der Klasse des statischen Konstruktors vorhanden sind, werden sie in der Textreihenfolge ausgeführt, in der sie in der Klassendeklaration angezeigt werden. Die Initialisierer werden unmittelbar vor dem statischen Konstruktor ausgeführt.

  • Wenn Sie keinen statischen Konstruktor zum Initialisieren statischer Felder bereitstellen, werden alle statischen Felder auf ihren Standardwert initialisiert.

  • Wenn ein statischer Konstruktor eine Ausnahme auslöst, ruft die Laufzeit sie nicht ein zweites Mal auf, und der Typ bleibt für die Lebensdauer der Anwendungsdomäne nicht initialisiert. In der Regel wird eine TypeInitializationException Ausnahme ausgelöst, wenn ein statischer Konstruktor einen Typ nicht instanziieren kann oder für eine unbehandelte Ausnahme, die in einem statischen Konstruktor auftritt. Bei statischen Konstruktoren, die nicht explizit im Quellcode definiert sind, ist bei der Problembehandlung möglicherweise eine Überprüfung des Il-Codes (Intermediate Language) erforderlich.

  • Das Vorhandensein eines statischen Konstruktors verhindert das Hinzufügen des attributs BeforeFieldInit Typ. Dies schränkt die Laufzeitoptimierung ein.

  • Ein als static readonly deklariertes Feld kann nur als Teil der Deklaration oder in einem statischen Konstruktor zugewiesen werden. Wenn kein expliziter statischer Konstruktor erforderlich ist, initialisieren Sie statische Felder bei der Deklaration anstelle eines statischen Konstruktors, um eine bessere Laufzeitoptimierung zu ermöglichen.

  • Die Laufzeit ruft einen statischen Konstruktor nicht mehr als einmal in einer einzigen Anwendungsdomäne auf. Dieser Aufruf erfolgt in einem gesperrten Bereich basierend auf dem spezifischen Typ der Klasse. Im Textkörper eines statischen Konstruktors sind keine zusätzlichen Sperrmechanismen erforderlich.

Anmerkung

Obwohl nicht direkt darauf zugegriffen werden kann, sollte das Vorhandensein eines expliziten statischen Konstruktors dokumentiert werden, um die Problembehandlung bei Initialisierungs exceptions zu unterstützen.