Freigeben über


Verwenden von Eigenschaften (C#-Programmierhandbuch)

Eigenschaften kombinieren Aspekte der Felder und der Methoden. Für Benutzer*innen eines Objekts scheint eine Eigenschaft ein Feld zu sein; der Zugriff auf die Eigenschaft erfordert dieselbe Syntax. Für die Implementierung einer Klasse besteht eine Eigenschaft aus ein oder zwei Codeblöcken, die ein get-Accessor und/oder ein set- oder init-Accessor darstellen. Der Codeblock für den get-Accessor wird ausgeführt, wenn die Eigenschaft gelesen wird. Der Codeblock für den set- oder den init-Accessor wird ausgeführt, wenn der Eigenschaft ein Wert zugewiesen wird. Eine Eigenschaft ohne einen set-Accessor ist schreibgeschützt. Eine Eigenschaft ohne einen get-Accessor ist lesegeschützt. Eine Eigenschaft, die beide Accessoren umfasst, ermöglicht Lese-/ Schreibzugriff. Sie können einen init-Accessor anstelle eines set-Accessors verwenden, damit die Eigenschaft als Teil der Objektinitialisierung festgelegt werden kann, andernfalls aber schreibgeschützt ist.

Im Gegensatz zu Feldern, werden Eigenschaften nicht als Variablen klassifiziert. Daher können Sie eine Eigenschaft nicht als ref- oder out-Parameter übergeben.

Eigenschaften haben viele Verwendungsmöglichkeiten:

  • Sie können Daten vor einer Änderung überprüfen.
  • Sie können Daten für eine Klasse transparent verfügbar machen, in der diese Daten aus einer anderen Quelle abgerufen werden, z. B. einer Datenbank.
  • Sie können eine Aktion ausführen, wenn Daten geändert werden, z. B. das Auslösen eines Ereignisses oder das Ändern des Werts anderer Felder.

Eigenschaften werden im Klassenblock deklariert, indem die Zugriffsebene des Felds angegeben wird, gefolgt vom Typ der Eigenschaft, gefolgt vom Namen der Eigenschaft und gefolgt von einem Codeblock, der einen get-Accessor und/oder einen set Accessor deklariert. Zum Beispiel:

public class Date
{
    private int _month = 7;  // Backing store

    public int Month
    {
        get => _month;
        set
        {
            if ((value > 0) && (value < 13))
            {
                _month = value;
            }
        }
    }
}

In diesem Beispiel wird Month als Eigenschaft so deklariert, dass der set-Accessor dafür sorgen kann, dass der Month-Wert zwischen 1 und 12 festgelegt wird. Die Month-Eigenschaft verwendet ein privates Feld, um den tatsächlichen Wert nachzuverfolgen. Der tatsächliche Speicherort der Daten einer Eigenschaft wird häufig als „Sicherungsspeicher“ der Eigenschaft bezeichnet. Es ist üblich, dass Eigenschaften private Felder als Sicherungsspeicher verwenden. Das Feld wird als privat gekennzeichnet um sicherzustellen, dass es nur durch Aufrufen der Eigenschaft geändert werden kann. Weitere Informationen zu öffentlichen und privaten Zugriffsbeschränkungen finden Sie unter Zugriffsmodifizierer. Automatisch implementierte Eigenschaften bieten eine vereinfachte Syntax für einfache Eigenschaftendeklarationen. Weitere Informationen finden Sie unter Automatisch implementierte Eigenschaften.

Ab C# 13 können Sie feldgesicherte Eigenschaften verwenden, um dem Accessor einer automatisch implementierten Eigenschaft eine set Überprüfung hinzuzufügen, wie im folgenden Beispiel gezeigt:

public class DateExample
{
    public int Month
    {
        get;
        set
        {
            if ((value > 0) && (value < 13))
            {
                field = value;
            }
        }
    }
}

Wichtig

Das field Schlüsselwort ist ein Vorschaufeature in C# 13. Sie müssen .NET 9 verwenden und das <LangVersion> Element preview in Der Projektdatei festlegen, um das field Kontextschlüsselwort zu verwenden.

Achten Sie darauf, die field Schlüsselwortfunktion in einer Klasse zu verwenden, die ein Feld mit dem Namen fieldhat. Das neue field Schlüsselwort schattiert ein Feld, das im Bereich eines Eigenschaftenaccessors benannt field ist. Sie können entweder den Namen der field Variablen ändern oder das @ Token verwenden, um auf den field Bezeichner zu verweisen als @field. Weitere Informationen erhalten Sie, indem Sie die Featurespezifikation für das field Schlüsselwort lesen.

Die get-Zugriffsmethode

Der Text des get Accessors ähnelt dem einer Methode. Er muss einen Wert des Eigenschaftentyps zurückgeben. Der C#-Compiler und der JIT-Compiler (Just-in-Time) erkennen allgemeine Muster für das Implementieren des get-Accessors und optimiert diese Muster. Beispielsweise ist ein get-Accessor, der ein Feld ohne Berechnung zurückgibt, wahrscheinlich für einen Speicherlesevorgang dieses Felds optimiert. Automatisch implementierte Eigenschaften folgen diesem Muster und profitieren von diesen Optimierungen. Allerdings kann ein virtueller get-Accessor nicht eingebettet werden, da der Compiler zum Zeitpunkt der Kompilierung nicht weiß, welche Methode zur Laufzeit tatsächlich aufgerufen wird. Das folgende Beispiel veranschaulicht eine get-Zugriffsmethode, die den Wert eines privaten Felds (_name) zurückgibt:

    class Employee
{
    private string _name;  // the name field
    public string Name => _name;     // the Name property
}

Wenn Sie auf die Eigenschaft, außer als Ziel einer Zuweisung, verweisen, wird der get-Accessor aufgerufen, um den Wert der Eigenschaft zu lesen. Zum Beispiel:

var employee= new Employee();
//...

System.Console.Write(employee.Name);  // the get accessor is invoked here

Der get-Accessor muss ein Ausdruckskörpermember sein oder in einer return- oder throw-Anweisung enden. Der Accessortext darf nicht ohne Rückgabewert verlassen werden.

Warnung

Im Allgemeinen ist es ein schlechter Programmierstil, um den Zustand des Objekts mithilfe des get Accessors zu ändern. Eine Ausnahme dieser Regel ist eine faul ausgewertete Eigenschaft, bei der der Wert einer Eigenschaft nur berechnet wird, wenn sie zum ersten Mal aufgerufen wird.

Der get-Accessor kann verwendet werden, um den Wert des Felds zurückzugeben, oder um den Wert des Felds zu berechnen und zurückgeben. Zum Beispiel:

class Manager
{
    private string _name;
    public string Name => _name != null ? _name : "NA";
}

Wenn Sie der Name-Eigenschaft im vorherigen Beispiel keinen Wert zuweisen, wird der Wert NA zurückgegeben.

Die set-Zugriffsmethode

Der set-Accessor ähnelt einer Methode, deren Rückgabetyp void ist. Er verwendet einen impliziten Parameter mit dem Namen value, dessen Typ der Typ der Eigenschaft ist. Der Compiler und der JIT-Compiler erkennen auch allgemeine Muster für einen set- oder init-Accessor. Diese allgemeinen Muster sind optimiert und schreiben den Speicher für das Unterstützungsfeld direkt. Im folgenden Beispiel wird ein set-Accessor der Name-Eigenschaft hinzugefügt.

class Student
{
    private string _name;  // the name field
    public string Name    // the Name property
    {
        get => _name;
        set => _name = value;
    }
}

Wenn Sie der Eigenschaft einen Wert zuweisen, wird der set-Accessor mit einem Argument aufgerufen, das den neuen Wert bereitstellt. Zum Beispiel:

var student = new Student();
student.Name = "Joe";  // the set accessor is invoked here

System.Console.Write(student.Name);  // the get accessor is invoked here

Das Verwenden des impliziten Parameternamens, value, für die Deklaration einer lokalen Variablen in einer set-Zugriffsmethode führt zu einem Fehler.

Die init-Zugriffsmethode

Der Code zum Erstellen einer init-Zugriffsmethode ist derselbe wie der Code zum Erstellen einer set-Zugriffsmethode, mit der Ausnahme, dass Sie das Schlüsselwort init anstelle von set verwenden. Der Unterschied besteht darin, dass die init-Zugriffsmethode nur im Konstruktor oder mithilfe eines Objektinitialisierers verwendet werden kann.

Hinweise

Eigenschaften können als public, private, protected, internal, protected internal oder private protected gekennzeichnet werden. Diese Zugriffsmodifizierer definieren, wie Benutzer der Klasse auf die Eigenschaft zugreifen können. Die get- und set-Accessors für dieselbe Eigenschaft können unterschiedliche Zugriffsmodifizierer aufweisen. Z. B. könnte get public sein, um den schreibgeschützten Zugriff von außerhalb des Typs zu ermöglichen, und set kann private oder protected sein. Weitere Informationen finden Sie unter Zugriffsmodifizierer.

Eine Eigenschaft kann mithilfe des static-Schlüsselworts als statische Eigenschaft deklariert werden. Statische Eigenschaften stehen Aufrufern jederzeit zur Verfügung, auch wenn keine Instanz der Klasse vorhanden ist. Weitere Informationen finden Sie unter Statische Klassen und statische Klassenmember.

Eine Eigenschaft kann mithilfe des Schlüsselworts virtual als virtuelle Eigenschaft gekennzeichnet werden. Virtuelle Eigenschaften ermöglichen es abgeleiteten Klassen, das Ereignisverhalten mit dem override-Schlüsselwort zu überschreiben. Weitere Informationen zu diesen Optionen finden Sie unter Vererbung.

Eine Eigenschaft, die eine virtuelle Eigenschaft überschreibt, kann auch versiegelt (sealed) werden, um anzugeben, dass sie für abgeleitete Klassen nicht mehr virtuell ist. Schließlich kann eine Eigenschaft als abstract(abstrakt) deklariert werden. Abstrakte Eigenschaften definieren keine Implementierung in der Klasse, sodass für abgeleitete Klassen eine eigene Implementierung geschrieben werden muss. Weitere Informationen zu abstrakten Klassen finden Sie unter Abstrakte und versiegelte Klassen und Klassenmember.

Hinweis

Das Verwenden eines virtual(virtuell)-, abstract(abstrakt)- oder override(außer Kraft setzen)- Modifizierers für einen Accessor einer statischen Eigenschaft ist ein Fehler.

Beispiele

Dieses Beispiel zeigt,Instanz-, statische- und schreibgeschützte Eigenschaften. Dieser Parameter akzeptiert den Namen des Mitarbeiters auf der Tastatur, Inkremente NumberOfEmployees durch 1, und zeigt den Mitarbeiternamen und die Nummer an.

public class Employee
{
    public static int NumberOfEmployees;
    private static int _counter;
    private string _name;

    // A read-write instance property:
    public string Name
    {
        get => _name;
        set => _name = value;
    }

    // A read-only static property:
    public static int Counter => _counter;

    // A Constructor:
    public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}

Beispiel für eine ausgeblendete Eigenschaft

In diesem Beispiel wird veranschaulicht, wie auf eine Eigenschaft in einer Basisklasse zugegriffen werden kann, die von einer anderen Eigenschaft ausgeblendet ist, die in einer abgeleiteten Klasse den gleichen Namen hat:

public class Employee
{
    private string _name;
    public string Name
    {
        get => _name;
        set => _name = value;
    }
}

public class Manager : Employee
{
    private string _name;

    // Notice the use of the new modifier:
    public new string Name
    {
        get => _name;
        set => _name = value + ", Manager";
    }
}

class TestHiding
{
    public static void Test()
    {
        Manager m1 = new Manager();

        // Derived class property.
        m1.Name = "John";

        // Base class property.
        ((Employee)m1).Name = "Mary";

        System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
        System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
    }
}
/* Output:
    Name in the derived class is: John, Manager
    Name in the base class is: Mary
*/

Die folgenden Punkte im vorherigen Beispiel sind wichtig:

  • Die Eigenschaft Name in der abgeleiteten Klasse blendet die Eigenschaft Name in der Basisklasse aus. In solch einem Fall wird der new-Modifizierer in der Deklaration der Eigenschaft in der abgeleiteten Klasse verwendet:
    public new string Name
    
  • Die Umwandlung (Employee) wird für den Zugriff auf die ausgeblendete Eigenschaft in der Basisklasse verwendet:
    ((Employee)m1).Name = "Mary";
    

Weitere Informationen zum Ausblenden von Mitgliedern finden Sie unter new-Modifizierer.

Beispiel für Überschreibungseigenschaft

In diesem Beispiel implementieren zwei Klassen Cube und Square eine abstrakte Klasse Shape, und überschreiben die abstrakte Area-Eigenschaft. Beachten Sie die Verwendung des überschreiben-Modifizierers in den Eigenschaften. Das Programm akzeptiert die Seite als Eingabe und berechnet die Bereiche für das Quadrat und den Cube. Das Programm akzeptiert auch den Bereich als Eingabe und berechnet die entsprechende Seite für das Quadrat und den Cube.

abstract class Shape
{
    public abstract double Area
    {
        get;
        set;
    }
}

class Square : Shape
{
    public double side;

    //constructor
    public Square(double s) => side = s;

    public override double Area
    {
        get => side * side;
        set => side = System.Math.Sqrt(value);
    }
}

class Cube : Shape
{
    public double side;

    //constructor
    public Cube(double s) => side = s;

    public override double Area
    {
        get => 6 * side * side;
        set => side = System.Math.Sqrt(value / 6);
    }
}

class TestShapes
{
    static void Main()
    {
        // Input the side:
        System.Console.Write("Enter the side: ");
        double side = double.Parse(System.Console.ReadLine());

        // Compute the areas:
        Square s = new Square(side);
        Cube c = new Cube(side);

        // Display the results:
        System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
        System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
        System.Console.WriteLine();

        // Input the area:
        System.Console.Write("Enter the area: ");
        double area = double.Parse(System.Console.ReadLine());

        // Compute the sides:
        s.Area = area;
        c.Area = area;

        // Display the results:
        System.Console.WriteLine("Side of the square = {0:F2}", s.side);
        System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
    }
}
/* Example Output:
    Enter the side: 4
    Area of the square = 16.00
    Area of the cube = 96.00

    Enter the area: 24
    Side of the square = 4.90
    Side of the cube = 2.00
*/

Siehe auch