Teilen über


Eigenschaften (C#-Programmierhandbuch)

Eine Eigenschaft ist ein Mitglied, das einen flexiblen Mechanismus zum Lesen, Schreiben oder Berechnen des Werts eines Datenfelds bietet. Eigenschaften werden als öffentliche Datenmitglied angezeigt, aber sie werden als spezielle Methoden implementiert, die als Accessoren bezeichnet werden. Dieses Feature ermöglicht den Aufrufern problemlosen Datenzugriff und unterstützt weiterhin die Sicherheit und Flexibilität der Daten. Die Syntax für Eigenschaften ist eine natürliche Erweiterung von Feldern. Ein Feld definiert einen Speicherort:

public class Person
{
    public string? FirstName;

    // Omitted for brevity.
}

Automatisch implementierte Eigenschaften

Eine Eigenschaftendefinition enthält Deklarationen für einen get- und set-Accessor, der den Wert dieser Eigenschaft abruft oder zuweist:

public class Person
{
    public string? FirstName { get; set; }

    // Omitted for brevity.
}

Das vorangehende Beispiel zeigt eine automatisch implementierte Eigenschaft. Der Compiler generiert ein ausgeblendetes Sicherungsfeld für die Eigenschaft. Der Compiler implementiert außerdem den Text der get- und set-Accessoren. Alle Attribute werden auf die automatisch implementierte Eigenschaft angewendet. Sie können das Attribut auf das vom Compiler generierte Sicherungsfeld anwenden, indem Sie das field:-Tag für das Attribut angeben.

Sie können eine Eigenschaft auf einen anderen Wert als den Standardwert initialisieren, indem Sie einen Wert nach der schließenden Klammer für die Eigenschaft festlegen. Möglicherweise bevorzugen Sie den Anfangswert für die Eigenschaft FirstName als leere Zeichenfolge und nicht null. Wie im folgenden Code dargestellt, geben Sie Folgendes an:

public class Person
{
    public string FirstName { get; set; } = string.Empty;

    // Omitted for brevity.
}

Zugriffssteuerung

In den vorherigen Beispielen wurden Lese-/Schreibeigenschaften gezeigt. Sie können auch schreibgeschützte Eigenschaften erstellen, oder den set- und get-Accessoren verschiedene Eingabehilfen geben. Angenommen, Ihre Person-Klasse sollte nur die Änderung des Werts der FirstName-Eigenschaft von anderen Methoden in dieser Klasse ermöglichen. Sie konnten dem set-Accessor private-Eingabehilfen anstelle von public geben:

public class Person
{
    public string? FirstName { get; private set; }

    // Omitted for brevity.
}

Die FirstName-Eigenschaft kann von einem beliebigen Code gelesen werden, aber sie kann nur von einem anderem Code in der Person-Klasse zugewiesen werden.

Sie können einen restriktiven Zugriffsmodifizierer zum set- oder get-Accessor hinzufügen. Ein Zugriffsmodifizierer für einen einzelnen Accessor muss restriktiver sein als der Zugriff auf die Eigenschaft. Der vorangehende Code ist zulässig, da die FirstName-Eigenschaft public ist, aber der set-Accessor ist private. Sie können keine private-Eigenschaft mit einer public-Zugriffsmethode deklarieren. Eigenschaftendeklarationen können ebenfalls als protected, internal, protected internal oder sogar private deklariert werden.

Es gibt zwei spezielle Zugriffsmodifizierer für set-Accessoren:

  • Ein set-Accessor kann über init als seinen Zugriffsmodifizierer verfügen. Dieser set-Accessor kann nur von einem Objektinitialisierer oder den Konstruktoren des Typs aufgerufen werden. Er ist restriktiver als private für den set-Accessor.
  • Eine automatisch implementierte Eigenschaft kann einen get Accessor ohne set Accessor deklarieren. In diesem Fall kann der Compiler den set-Accessor nur aus den Konstruktoren des Typs aufrufen. Er ist restriktiver als der init-Accessor auf dem set-Accessor.

Ändern Sie die Person-Klasse folgendermaßen:

public class Person
{
    public Person(string firstName) => FirstName = firstName;

    public string FirstName { get; }

    // Omitted for brevity.
}

Im obigen Beispiel müssen Aufrufer den Konstruktor verwenden, der den FirstName-Parameter enthält. Aufrufer können keine Objektinitialisierer verwenden, um der Eigenschaft einen Wert zuzuweisen. Um Initialisierer zu unterstützen, können Sie die set-Zugriffsmethode zu einer init-Zugriffsmethode machen, wie im folgenden Code gezeigt:

public class Person
{
    public Person() { }
    public Person(string firstName) => FirstName = firstName;

    public string? FirstName { get; init; }

    // Omitted for brevity.
}

Diese Modifizierer werden häufig mit dem required-Modifizierer verwendet, um die ordnungsgemäße Initialisierung zu erzwingen.

Erforderliche Eigenschaften

Im vorherigen Beispiel kann ein Aufrufer eine Person mit dem Standardkonstruktor erstellen, ohne die FirstName-Eigenschaft festzulegen. Der Eigenschaftstyp wurde in die Zeichenfolge nullable geändert. Ab C# 11 können Sie erforderlich machen, dass Aufrufer eine Eigenschaft festlegen:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName) => FirstName = firstName;

    public required string FirstName { get; init; }

    // Omitted for brevity.
}

Mit dem vorherigen Code werden zwei Änderungen an der Person-Klasse vorgenommen. Erstens enthält die Deklaration der FirstName-Eigenschaft den required-Modifizierer. Das bedeutet, dass jeder Code, der eine neue Person erstellt, diese Eigenschaft mithilfe eines Objektinitialisierers festlegen muss. Zweitens verfügt der Konstruktor, der einen firstName-Parameter annimmt, über das System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute-Attribut. Dieses Attribut informiert den Compiler darüber, dass dieser Konstruktor alle required-Member festlegt. Aufrufer, die diesen Konstruktor verwenden, müssen keine required-Eigenschaften mit einem Objektinitialisierer festlegen.

Wichtig

Verwechseln Sie required nicht mit non-nullable. Es ist zulässig, eine required-Eigenschaft auf null oder default festzulegen. Wenn der Typ non-nullable ist, wie string in diesen Beispielen, gibt der Compiler eine Warnung aus.

var aPerson = new Person("John");
aPerson = new Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();

Ausdruckstextdefinitionen

Eigenschaftsaccessoren bestehen häufig aus einzeiligen Anweisungen. Die Accessoren weisen das Ergebnis eines Ausdrucks zu oder geben es zurück. Sie können diese Eigenschaften als Ausdruckskörpermember implementieren. Ausdruckstextdefinitionen bestehen aus dem =>-Token, gefolgt von dem Ausdruck, der der Eigenschaft zugewiesen oder aus dieser abgerufen werden soll.

Schreibgeschützte Eigenschaften können die get-Zugriffsmethode als Ausdruckskörpermember implementieren. Das folgende Beispiel implementiert die schreibgeschützte Name-Eigenschaft als ein Ausdruckskörpermember:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    public string Name => $"{FirstName} {LastName}";

    // Omitted for brevity.
}

Bei der Name-Eigenschaft handelt es sich um eine berechnete Eigenschaft. Es gibt kein Sicherungsfeld für Name. Die Eigenschaft berechnet es jedes Mal neu.

Eigenschaften mit Unterstützungsfeldern

Sie können das Konzept einer berechneten Eigenschaft mit einem privaten Feld mischen und eine zwischengespeicherte ausgewertete Eigenschaft erstellen. Aktualisieren Sie z. B. die Eigenschaft FullName so, dass die Zeichenfolgenformatierung beim ersten Zugriff erfolgt:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Diese Implementierung funktioniert, da die Eigenschaften FirstName und LastName schreibgeschützt sind. Personen können ihren Namen ändern. Beim Aktualisieren der Eigenschaften FirstName und LastName, damit sie set-Accessoren zulassen, müssen Sie alle zwischengespeicherten Werte für fullName ungültig machen. Sie müssen die set-Accessoren der Eigenschaften FirstName und LastName aktualisieren, damit das fullName-Feld erneut berechnet wird:

public class Person
{
    private string? _firstName;
    public string? FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            _fullName = null;
        }
    }

    private string? _lastName;
    public string? LastName
    {
        get => _lastName;
        set
        {
            _lastName = value;
            _fullName = null;
        }
    }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Diese endgültige Version wertet die FullName-Eigenschaft nur bei Bedarf aus. Die zuvor berechnete Version wird verwendet, wenn sie gültig ist. Andernfalls aktualisiert die Berechnung den zwischengespeicherten Wert. Entwickler, die diese Klasse verwenden, müssen die Details der Implementierung nicht kennen. Keine dieser interne Änderungen hat Einfluss auf die Verwendung des Person-Objekts.

Ab C# 13 können Sie partial-Eigenschaften in partial-Klassen erstellen. Die Implementierungsdeklaration für eine partial Eigenschaft kann keine automatisch implementierte Eigenschaft sein. Eine automatisch implementierte Eigenschaft verwendet dieselbe Syntax wie eine deklarierende partielle Eigenschaftsdeklaration.

Eigenschaften

Eigenschaften sind eine Form intelligenter Felder in einer Klasse oder einem Objekt. Außerhalb des Objekts wirken diese wie Felder in dem Objekt. Eigenschaften können jedoch mithilfe der vollständigen Palette der C#-Funktionalität implementiert werden. Sie können Überprüfung, verschiedene Eingabehilfen, verzögerte Auswertung oder alle Anforderungen, die Ihre Szenarios benötigen, bereitstellen.

  • Einfache Eigenschaften, die keinen benutzerdefinierten Accessorcode erfordern, können entweder als Ausdruckstextdefinitionen oder als automatisch implementierte Eigenschaften implementiert werden.
  • Mithilfe von Eigenschaften kann eine Klasse eine öffentliche Methode zum Abrufen und Festlegen von Werten verfügbar machen und dabei den Implementierungs- oder Verifizierungscode ausblenden.
  • Eine get-Eigenschaftenaccessor wird verwendet, um den Wert der Eigenschaft zurückzugeben. Ein set-Eigenschaftenaccessor wird verwendet, um einen neuen Wert zuzuweisen. Eine init-Eigenschaftenzugriffsmethode wird verwendet, um nur während der Objekterstellung einen neuen Wert zuzuweisen. Diese Zugriffsmethoden können über verschiedene Zugriffsebenen verfügen. Weitere Informationen finden Sie unter Einschränken des Accessorzugriffs.
  • Das Schlüsselwort value wird verwendet, um den Wert zu definieren, der von einer der Zugriffsmethoden set oder init zugewiesen wird.
  • Eigenschaften können sein: Lesen/Schreiben (beide verfügen über einen get- und set-Accessor), schreibgeschützt (verfügen über einen get-Accessor, jedoch keinen set-Accessor), oder lesegeschützt (verfügen über einen set-Accessor, jedoch keinen get Accessor). Schreibgeschützte Eigenschaften sind selten.

C#-Programmiersprachenspezifikation

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

Siehe auch