Verwenden von Eigenschaften (C#-Programmierhandbuch)

Aktualisiert: November 2007

Eigenschaften beinhalten sowohl Aspekte von Feldern als auch von Methoden. Dem Benutzer eines Objekts erscheint eine Eigenschaft wie ein Feld. Um auf die Eigenschaft zugreifen zu können, ist dieselbe Syntax erforderlich. Für den Implementierer einer Klasse besteht eine Eigenschaft aus einem oder zwei Codeblöcken, die einen get-Accessor und/oder einen set-Accessor darstellen. Der Codeblock für den get-Accessor wird ausgeführt, wenn die Eigenschaft gelesen wird. Der Codeblock für den set-Accessor wird ausgeführt, wenn der Eigenschaft ein neuer Wert zugeordnet wird. Eine Eigenschaft ohne einen set-Accessor gilt als schreibgeschützt. Eine Eigenschaft ohne einen get-Accessor gilt als lesegeschützt. Eine Eigenschaft mit beiden Accessoren ermöglicht Lese- und Schreibzugriff.

Im Gegensatz zu Feldern werden Eigenschaften nicht als Variablen klassifiziert. Aus diesem Grund können Sie Eigenschaften nicht als Parameter ref (C#-Referenz) oder out (C#-Referenz) übergeben.

Eigenschaften haben viele Verwendungszwecke: Sie können Daten überprüfen, bevor eine Änderung zugelassen wird. Sie können Daten in einer Klasse auf transparente Weise verfügbar machen, wobei diese Daten in Wirklichkeit von einer anderen Quelle abgefragt werden, z. B. einer Datenbank. Sie können eine Aktion durchführen, wenn Daten verändert werden, z. B. ein Ereignis auslösen oder Werte anderer Felder verändern.

Eigenschaften werden innerhalb des Klassenblocks definiert, indem die Zugriffsebene des Felds angegeben wird, gefolgt vom Typ und dem Namen der Eigenschaft sowie von einem Codeblock, der einen get-Accessor und/oder einen set-Accessor deklariert. Beispiel:

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

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

In diesem Beispiel wird Month als Eigenschaft deklariert, damit der set-Accessor dafür sorgen kann, dass der Month-Wert zwischen 1 und 12 festgelegt wird. Die Month-Eigenschaft verwendet ein privates Feld zur Kontrolle des tatsächlichen Werts. Der tatsächliche Speicherort, an dem die Daten einer Eigenschaft gespeichert werden, wird oft als "Sicherungsspeicher" der Eigenschaft bezeichnet. Es ist üblich, dass Eigenschaften private Felder als Sicherungsspeicher verwenden. Das Feld wird als privat gekennzeichnet, damit sichergestellt ist, dass eine Änderung des Felds nur durch Aufrufen der Eigenschaft durchgeführt werden kann. Weitere Informationen über öffentliche und private Zugriffsbeschränkungen finden Sie unter Zugriffsmodifizierer (C#-Programmierhandbuch).

Automatisch implementierte Eigenschaften stellen vereinfachte Syntax für einfache Eigenschaftendeklarationen bereit. Weitere Informationen finden Sie unter Automatisch implementierte Eigenschaften (C#-Programmierhandbuch).

get-Accessor

Der Text des get-Accessors ähnelt dem Text einer Methode. Er muss einen Wert des Eigenschaftentyps zurückgeben. Die Ausführung des get-Accessors entspricht dem Lesen des Feldwerts. Wenn Sie z. B. die private Variable von dem get-Accessor zurückgeben und Optimierungen aktiviert sind, wird der Aufruf an die get-Accessormethode durch den Compiler eingebettet, damit kein zusätzlicher Aufwand an Methodenaufrufen entsteht. Eine virtuelle get-Accessormethode kann jedoch nicht eingebettet werden, da zur Kompilierzeit im Compiler nicht bekannt ist, welche Methode während der Laufzeit tatsächlich aufgerufen wird. Das folgende Beispiel enthält einen get-Accessor, der den Wert des privaten Felds name zurückgibt:

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
    }
}

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

Person person = new Person();
//...

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

Der get-Accessor muss mit einer return-Anweisung oder einer throw-Anweisung enden, und die Steuerung darf nicht über den Accessortext hinausgehen.

Beim Programmieren sollte vermieden werden, den Zustand des Objekts mit dem get-Accessor zu ändern. Der folgende Accessor hat beispielsweise den Nebeneffekt, dass der Zustand des Objekts bei jedem Zugriff auf das number-Feld geändert wird.

private int number;
public int Number
{
    get
    {
        return number++;   // Don't do this
    }
}

Der get-Accessor kann verwendet werden, um entweder den Feldwert zurückzugeben oder um den Feldwert zu berechnen und zurückzugeben. Beispiele:

class Employee
{
    private string name;
    public string Name
    {
        get
        {
            return name != null ? name : "NA";
        }
    }
}

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

set-Accessor

Der set-Accessor kann mit einer Methode verglichen werden, deren Rückgabetyp void ist. Er verwendet einen impliziten Parameter mit der Bezeichnung value, dessen Typ dem Typ der Eigenschaft entspricht. Im folgenden Beispiel wird ein set-Accessor der Name-Eigenschaft hinzugefügt:

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

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

Person person = new Person();
person.Name = "Joe";  // the set accessor is invoked here                

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

Es wäre falsch, den impliziten Parameternamen (value) für die Deklaration einer lokalen Variablen in einem set-Accessor zu verwenden.

Hinweise

Eigenschaften können als public, private, protected, internal und protected internal gekennzeichnet sein. Diese Zugriffsmodifizierer definieren, wie Benutzer der Klasse auf die Eigenschaft zugreifen können. Der get-Accessor und der set-Accessor haben für die gleiche Eigenschaft möglicherweise verschiedene Zugriffsmodifizierer. So kann get zum Beispiel public sein, um den schreibgeschützten Zugriff von außerhalb des Typs zuzulassen, und set kann möglicherweise private oder protected sein. Weitere Informationen finden Sie unter Zugriffsmodifizierer (C#-Programmierhandbuch).

Eine Eigenschaft kann mit dem static-Schlüsselwort als statische Eigenschaft deklariert werden. Dadurch ist die Eigenschaft jederzeit für Aufrufer verfügbar, selbst wenn keine Instanz der Klasse vorhanden ist. Weitere Informationen finden Sie unter Statische Klassen und statische Klassenmember (C#-Programmierhandbuch).

Eine Eigenschaft kann mit dem virtual-Schlüsselwort als virtuelle Eigenschaft gekennzeichnet werden. Dies ermöglicht abgeleiteten Klassen, das Verhalten von Eigenschaften mit dem override-Schlüsselwort zu überschreiben. Weitere Informationen zu diesen Optionen finden Sie unter Vererbung (C#-Programmierhandbuch).

Eine Eigenschaft, die eine virtuelle Eigenschaft überschreibt, kann ebenfalls sealed sein. Damit ist sie für abgeleitete Klassen nicht mehr virtuell. Und nicht zuletzt kann eine Eigenschaft als abstract deklariert werden. Dies bedeutet, dass die Klasse keine Implementierung enthält, sodass abgeleitete Klassen eine eigene Implementierung schreiben müssen. Weitere Informationen zu diesen Optionen finden Sie unter Abstrakte und versiegelte Klassen und Klassenmember (C#-Programmierhandbuch).

Hinweis:

Es wird ein Fehler verursacht, wenn einer der Modifizierer virtual (C#-Referenz), abstract (C#-Referenz) oder override (C#-Referenz) für einen Accessor einer static-Eigenschaft verwendet wird.

Beispiel

Dieses Beispiel veranschaulicht die Verwendung von Instanzeigenschaften, statischen Eigenschaften und Nur-Lesen-Eigenschaften. Die Eingabe des Mitarbeiternamens über die Tastatur wird akzeptiert, NumberOfEmployees wird um 1 erhöht, und der Name sowie die Nummer des Mitarbeiters werden angezeigt.

public class Employee
{
    public static int NumberOfEmployees;
    private static int counter;
    private string name;

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

    // A read-only static property:
    public static int Counter
    {
        get { return counter; }
    }

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

class TestEmployee
{
    static void Main()
    {
        Employee.NumberOfEmployees = 107;
        Employee e1 = new Employee();
        e1.Name = "Claude Vige";

        System.Console.WriteLine("Employee number: {0}", Employee.Counter);
        System.Console.WriteLine("Employee name: {0}", e1.Name);
    }
}
/* Output:
    Employee number: 108
    Employee name: Claude Vige
*/

Dieses Beispiel zeigt, wie auf eine Eigenschaft in einer Basisklasse zugegriffen wird, die durch eine andere Eigenschaft mit demselben Namen in einer abgeleiteten Klasse verborgen wird.

public class Employee
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

public class Manager : Employee
{
    private string name;

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

class TestHiding
{
    static void Main()
    {
        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
*/

Im Folgenden werden einige wichtige Aspekte erläutert, die im oben aufgeführten Beispiel enthalten sind:

  • Die Name-Eigenschaft in der Basisklasse wird durch die Name-Eigenschaft in der abgeleiteten Klasse verborgen. In einem solchen Fall wird der new-Modifizierer für die Deklaration der Eigenschaft in der abgeleiteten Klasse verwendet:

    public new string Name
    
  • Die Umwandlung (Employee) wird verwendet, um auf die verborgene Eigenschaft in der Basisklasse zuzugreifen:

    ((Employee)m1).Name = "Mary";
    

    Weitere Informationen zum Ausblenden von Membern finden Sie unter new-Modifizierer (C#-Referenz).

In diesem Beispiel wird durch die beiden Klassen Cube und Square die abstrakte Shape-Klasse implementiert. Zusätzlich wird deren abstrakte Area-Eigenschaft überschrieben. Beachten Sie die Verwendung des override-Modifizierers für die Eigenschaften. Die Seitenlänge wird vom Programm als Eingabe akzeptiert, und die Oberfläche des Quadrats und des Würfels werden berechnet. Auch die Oberfläche wird als Eingabe akzeptiert, und die entsprechende Seitenlänge des Quadrats und des Würfels wird berechnet.

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

class Square : Shape
{
    public double side;

    public Square(double s)  //constructor
    {
        side = s;
    }

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

class Cube : Shape
{
    public double side;

    public Cube(double s)
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return 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

Aufgaben

Beispiel für Eigenschaften

Konzepte

C#-Programmierhandbuch

Referenz

Eigenschaften (C#-Programmierhandbuch)

Schnittstelleneigenschaften (C#-Programmierhandbuch)

Automatisch implementierte Eigenschaften (C#-Programmierhandbuch)