name
ist nur über die beiden Methoden GetName()
und SetName()
möglich. Sollte sich einmal ein "unerwarteter" Wert
in der Variablen befinden, müssen Sie nur in der Methode SetName()
"warten" (z.B. über einen Haltepunkt im Debugger), bis der fehlerhafte Wert als Parameter übergeben wird. Außerdem
können Sie in der Set-Methode gleich den übergebenen Parameter validieren (überprüfen). In diesem Beispiel wird der Variablen name
z.B. kein Wert zugewiesen, wenn der Methode SetName()
eine leere Zeichenkette übergeben wird. Innerhalb der Get-Methode wird einfach der in der Variablen name
gespeicherte Wert zurückgegeben. Allerdings wäre es auch möglich, diesen vorher noch
entsprechend zu formatieren.
public class Person { private string name; public void SetName(string name) { if(name != "") this.name = name; } public string GetName() { return name; } }
INFO
Eigenschaften können dadurch auch genutzt werden, um Datenbankverbindungen oder Dateien zu öffnen und zu schließen. Durch das Setzen einer Eigenschaft wieActive
oder Enabled
wird eine Methode aufgerufen, welche die Verbindung herstellt bzw. trennt. In der dahinter liegenden (optionalen) Variablen, die dann meist einen booleschen Typ besitzt, wird nur
der aktuelle Zustand hinterlegt, z.B. true
, für eine geöffnete Verbindung.Person
verwaltet Informationen zu einer Person, in diesem Beispiel nur den Namen. Die Instanzvariable name
, welche den Wert tatsächlich speichert, wurde als private
deklariert, so dass sie nicht direkt manipuliert werden kann. Stattdessen wird eine Eigenschaft Name
bereitgestellt. Diese liefert über einen so genannten get-Accessor den Wert der Variablen
name
zurück. Über einen so genannten set-Accessor wird der Wert der Variablen (nach vorheriger Prüfung des übergebenen Wertes) geschrieben. Auf den Wert, der in der Zeile
p.Name = ...
der Eigenschaft zugewiesen wird, kann im set-Accessor über das reservierte Wort value
zugegriffen werden.
using System; namespace CSharpBuch.Kap12 { public class EinfacheEigenschaften { static void Main(string[] args) { Person p = new Person(); p.Name = "Meier"; } } public class Person { private string name; public string Name { get { return name; } set { if(value != "") name = value; } } } }Listing 12.1: EinfacheEigenschaften.cs
{
und }
eingeschlossen.
get
eingeleitet und in geschweifte Klammern eingeschlossen.
Wie in einer Methode ist die Angabe von return
mit einem Rückgabewert entsprechend des Typs der Eigenschaft notwendig.
set
eingeleitet. Auf den zugewiesenen Wert wird über das reservierte Schlüsselwort value
zugegriffen.
get
und set
werden auch als get- und set-Accessoren bezeichnet.
get
oder set
weglassen, entsteht eine nicht lesbare bzw. eine schreibgeschützte Eigenschaft.
ref
oder out
an Methoden übergeben werden, da es sich ja eigentlich um Methoden handelt.
new
überschreiben.
INFO
Eine Eigenschaft wird mit einem Bezeichner in Pascalschreibweise deklariert. Wird eine Variable benötigt, die den aktuellen Wert der Eigenschaft repräsentiert, wird diese in der Regel alsprivate
und in Kamelschreibweise, also beginnend mit einem Kleinbuchstaben, mit dem ansonsten gleichen Bezeichnernamen deklariert. privateDiese einfache Logik kann auch der Compiler generieren. Dazu wird vom Compiler eine private, anonyme Variable zur Aufnahme des Wertes bereitgestellt, die gelesen und geschrieben wird. Der direkte Zugriff auf diese Variable ist nicht möglich. Die Get- und Set-Methoden sind automatisch öffentlich. Einzige Ausnahme ist, dass Sie vor der Set-Methode den Modifizierername; public Name { get { return name; } set { name = value; } }
private
setzen können,
um eine schreibgeschützte Eigenschaft zu erhalten. Das Weglassen der Get- oder der Set-Methode ist nicht möglich.
publicName { get; set; } public Name { get; private set; }
get
und set
angegeben werden, und zwar mit unterschiedlichen Rechten. In der Regel wird dies zur Definition von Einschränkungen
beim set-Accessor genutzt, den dann nur abgeleitete Klassen verwenden können.
Name
wird nur noch abgeleiteten Klassen erlaubt.
public string Name { get { return name; } protected set { name = value; } }
get
oder set
einen Zugriffsmodifizierer an.
get
oder bei set
erlaubt. Der jeweils andere Accessor verwendet die Angabe bei der Deklaration der Eigenschaft. Außerdem
können Sie einen Modifizierer an einem Accessor nur dann angeben, wenn beide Accessoren verwendet werden.
get
oder set
verwendete Zugriffsmodifizierer muss die Zugriffsrechte stärker einschränken als der Modifizierer in der Deklaration der Eigenschaft.
get
oder set
lediglich ein Semikolon gesetzt. Der Rest der Eigenschaftsdeklaration bleibt gleich. Sie können in einer Schnittstelle auch nur die
get- oder set-Accessoren vorgeben. Eine Klasse, welche die Schnittstelle implementiert, kann dann den anderen Accessor ebenfalls zur Verfügung stellen. Für die Schnittstellenimplementierung wäre es aber
nicht notwendig.
IKlassenInfo
deklariert eine Eigenschaft Version
. Klassen, welche die Schnittstelle implementieren, geben darüber ihre interne Versionsnummer zurück. Das
Datenelement, welches die Version tatsächlich speichert, wird in der Klasse Konto
mit dem Namen version
bereitgestellt. Außerdem enthält die Klasse eine statische Eigenschaft
Autor
, um unabhängig von einem Objekt den Autor (bzw. den Entwickler) einer Klasse zu ermitteln.
using System; namespace CSharpBuch.Kap12 { public class EigenschaftenInSchnittstellen { static void Main(string[] args) { Konto ie = new Konto(); Konto.Autor = "Dirk F."; ie.Version = "0.01"; Console.WriteLine("Autor: " + Konto.Autor); Console.WriteLine("Version: " + ie.Version); } } public interface IKlassenInfo { string Version { get; set; } } public class Konto: IKlassenInfo { private string version; private static string autor; public string Version { get { return version; } set { version = value; } } public static string Autor { get { return autor; } set { autor = value; } } } }
Daten
besitzt ein Array datenFeld
, in dem Strings verwaltet werden. Für dieses Feld werden über einen Indexer ein Lese- und ein Schreibzugriff bereitgestellt.
Der Indexer wird durch Angabe des Zugriffsmodifizierers, des Rückgabetyps und des Schlüsselworts this
deklariert. Er besitzt also keinen eigenen Namen, sondern wird über ein Objekt der
Klasse angesprochen. In eckigen Klammern wird der Parameter des Indexers angegeben, der dann in den get- und set-Accessoren zum Auffinden des passenden Elements genutzt werden kann.
public class Daten { string[] datenFeld = { "", "", "" }; public string this[int index] { get { return datenFeld[index]; } set { datenFeld[index] = value; } } }
this
verwendet. Damit kann der Indexer über ein Objekt der Klasse aufgerufen werden.
this
wird in eckigen Klammern der Typ und ein Bezeichner für den Index angegeben. Über den Index kann dann das gewünschte Datenelement identifiziert werden.
public string this[int zeile, int spalte]
,
um beispielsweise einen Wert aus einer Tabelle zurückzuliefern.
value
zu.
ref
- oder out
-Parameter an Methoden übergeben werden.
INFO
In der API-Dokumentation verbirgt sich ein Indexer unter einer Eigenschaft mit dem NamenItem
. Diese Eigenschaft existiert nicht tatsächlich, wenn
Sie mit C# programmieren, da C# Indexer direkt unterstützt. Die Eigenschaft ist nur dann über diesen Namen verfügbar, wenn eine .NET-Programmiersprache keine Indexer unterstützt. Über das Attribut
IndexerName
könnten Sie einen anderen Standardnamen für den Indexer definieren.Lottozahlen
dient zur Simulierung einer Lottoziehung. Dazu werden im Konstruktor der Klasse die Anzahl der benötigten Zahlen und der Maximalwert übergeben. Über die
Methode ZiehungDurchfuehren()
werden die benötigten Zufallszahlen erzeugt (ohne Rücksicht auf doppelt gezogene Zahlen). Damit die "berechneten" Zahlen einfach bereitgestellt werden
können, wird ein Indexer deklariert. Dieser erhält als Parameter den Null-basierten Index für das Array ziehung mit den gezogenen Zahlen. Im get-Accessor wird außerdem eine minimale
Überprüfung des Indexwertes vorgenommen.
using System; namespace CSharpBuch.Kap12 { public class KlassenIndizieren { static void Main(string[] args) { Lottozahlen lz = new Lottozahlen(5, 35); lz.ZiehungDurchfuehren(); for(int zahl = 0; zahl < 5; zahl++) Console.WriteLine("Gezogen wurde: {0}", lz[zahl]); } } public class Lottozahlen { private int[] ziehung; private int anzahl; private int maxWert; public Lottozahlen(int anzahl, int maxWert) { this.maxWert = maxWert; this.anzahl = anzahl; } public int this[int index] { get { if((index >= 0) & (index < anzahl)) return ziehung[index]; else return 0; } } public void ZiehungDurchfuehren() { Random rd = new Random(DateTime.Now.Millisecond); ziehung = new int[anzahl]; for(int i = 0; i < anzahl; i++ ) ziehung[i] = rd.Next(maxWert) + 1; } } }Listing 12.3: KlassenIndizieren.cs
INFO
Das hier gezeigte Beispiel führt nur rudimentäre Prüfungen der Index- und sonstigen Parameterwerte durch. Stellen Sie bei Verwendung eines Indexers sicher, dass die Indexwerte auch verfügbar sind. Implementieren Sie gegebenenfalls eine EigenschaftCount
(oder Anzahl
), welche die Anzahl der über den Index verfügbaren Elemente zurückgibt. ILotto
erlaubt den lesenden und schreibenden Zugriff auf die erzeugten Lottozahlen. Über den schreibenden Zugriff könnten Sie eventuell später etwas nachhelfen, wenn Sie nur zwei Richtige haben.
public interface ILotto { int this[int index] { get; set; } void ZiehungDurchfuehren(); }
Eigenschaften | Indexer |
Beide werden wie Variablen verwendet. Zur Wertzuweisung bzw. -rückgabe werden aber immer Methoden verwendet. Es ist möglich, nur einen lesenden oder schreibenden Zugriff bereitzustellen. | |
Beide dürfen nicht per ref oder out an Methoden übergeben werden. | |
Der Zugriff auf eine Eigenschaft erfolgt über einen Namen. | Der Zugriff auf den Indexer erfolgt wie bei einem Array (eckige Klammern) bzw. einer Methode (ein bis mehrere Indexparameter werden durch Komma getrennt übergeben). |
Eigenschaften können statisch wie auch innerhalb der Objektinstanz deklariert werden. | Indexer sind immer mit einer Instanz verbunden. |
Als Parameter wird nur der neue Wert der Eigenschaft im set-Accessor übergeben. | In einem Indexer erhalten die get- und set-Accessoren die in eckigen Klammern übergebenen Parameter.
Der set-Accessor erhält bei Zuweisungen an den Indexer noch den übergebenen Wert über das Schlüsselwort value . |
Verwenden Sie Eigenschaften, um einen über Methoden abgesicherten lesenden und schreibenden Zugriff auf Datenmember durchzuführen. Kapseln Sie komplexe Operationen wie das Herstellen einer Datenbankverbindung in einer Eigenschaft, um die Programmierung zu vereinfachen. | Verwenden Sie Indexer, wenn Sie einen einfachen, indexbasierten Zugriff auf die durch eine Klasse verwalteten Datenelemente bereitstellen wollen. Diese Vorgehensweise wird sehr häufig in den Auflistungsklassen verwendet (sieht Kapitel "Auflistungen"). |
Zufallszahl
, die eine Eigenschaft Zahl
besitzt. Diese Eigenschaft soll nur lesbar sein und bei jedem Lesezugriff eine Zufallszahl im Bereich von 1 bis 100 liefern.
Tag
, Monat
und Jahr
definiert. Implementieren Sie die Schnittstelle in einer Klasse Datum
.
Überprüfen Sie beim Setzen der Eigenschaften, dass die übergebenen Werte plausibel sind.
MeineAutos
verwaltet über ein Array aus 5 Elementen vom Typ Auto
Daten Ihrer vergangenen (oder zukünftigen) PKWs. Die dazu benötigte Klasse Auto
sollte einige sinnvolle Eigenschaften besitzen.
Über eine Eigenschaft Count
liefert die Klasse die Anzahl der verwalteten Autos zurück (es müssen ja nicht wie hier in der Übung immer genau 5 Autos sein). Die Klasse stellt einen Indexer
zur Verfügung, um auf die einzelnen Auto-Objekte zugreifen zu können. Testen Sie die Funktionsweise.