TOC

This article is currently in the process of being translated into German (~85% done).

Klassen:

Eigenschaften

Im vorherigen Artikel haben wir Felder diskutiert. Sie sind wie eine globale Variable für eine Klasse, welche dir Zugang erlaubt von allen Methoden aus. Wir haben auch kurz über die Felder diskutiert, welche von anderen Klassen aus zugegriffen werden können wenn diese als public (=öffentlich) markiert sind, das zu tun wird jedoch nicht empfohlen. Für Variablen/Felder auf welche du von außerhalb deiner Klasse zugreifen willst kannst du stattdessen properties benutzen.

Wenn du ein Feld als öffentlich bezeichnest, ermöglichst du den kompletten Zugriff auf dieses Feld von außen - andere Klassen können damit tun was immer sie wollen, ohne die zugewiesene Klasse zu beachten. Eigenschaften - sogenannte ,,properties" - geben die Kontrolle an die zugewiesene Klasse wieder zurück, indem ein Feld als nur "lesbar"- oder "schreibar" spezifiziert wird, und ermöglicht dann der deklarierenden Klasse, den Wert zuvor zu überprüfen und zu manipulieren, bevor der Wert zurückgegeben oder dem Feld zugeordnet wird.

Eine Eigenschaft ist ein wenig wie eine Mischung aus einem Feld und einer Methode, weil es sehr ähnlich wie ein Feld deklariert wird mit der Sichtbarkeit, einem Datentyp und einem Namen, aber hat auch einen Körper wie eine Methode um das Verhalten zu steuern:

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Beachten Sie die speziellen get und set Schlüsselwörter. Sie werden explizit für Eigenschaften benutzt, um das Verhalten beim lesen (get'ing) und schreiben (set'ing) eines Feldes zu kontrollieren. Du kannst Eigenschaften auch nur mit einer get-Implementation ODER einer set-Implementation haben, um Eigenschaften dementsprechend Schreibgeschützt oder Lesegeschützt zu kreieren. Zusätzlich kannst du auch die Visibilität der get- und set-Implementationen kontrollieren, zum Beispiel kann die Eigenschaft von überall gelesen (public), aber nur in der eigenen Klasse modifiziert werden (private).

Du wirst außerdem bemerken, dass ich auf ein Feld namens _name referenziere. Dieses wirst du in deiner Klasse auch deklarieren müssen, sodass deine Property es benutzen kann. Ein gebräuchliches Muster für Felder und Properties sieht folgendermaßen aus.:

private string _name = "John Doe";

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Nun kannst du sehen wie das Feld und die Eigenschaft zusammenarbeiten. Die get Methode gibt den Wert des _name Feldes zurück, während die set Methode den übergebenen Wert dem _name Feld zuweist. In der Set- Methode verwenden wir gewöhnlich das besondere Schlüsselwort value, welches in dieser besonderen Situation auf den Wert verweist, der dann die Eigenschaft übergeben wird.

Also, das ist im Prinzip so einfach wie es nur geht und an diesem Punkt haben wir noch nichts getan, was nicht auch mit einem einfachen öffentlichen Feld getan werden könnte. Aber an einem späteren Punkt könntest du entscheiden, dass du mehr Kontrolle darüber nehmen möchtest, wie andere Klassen mit dem Namen arbeiten können. Und da du dies als Eigenschaft eingebaut hast, kannst du diese Implementierung ohne Probleme modifizieren, ohne jemanden, der deine Klasse benutzt, dabei zu stören. Zum Beispiel kann die Name Eigenschaft verändert werden, um so auszusehen:

private string _name = "John Doe";

public string Name
{
	get 
	{
		return _name.ToUpper();
	}
	set 
	{
		if(!value.Contains(" "))
			throw new Exception("Please specify both first and last name!");
		_name = value; 
	}
}

Die getter-Methode erzwingt jetzt, dass der Rückgabewert immer in GROSSBUCHSTABEN geliefert wird, unabhängig davon, ob im zugrundeliegenden Feld (_name) Großbuchstaben und / oder Kleinbuchstaben verwendet wurden. In der setter-Methode haben wir einige Codezeilen hinzugefügt, um zu überprüfen, ob der übergebene Wert ein Leerzeichen enthält, denn wir haben entschieden, dass der Name immer aus beidem, einen Vornamen und einem Nachnamen bestehen soll. Falls dies nicht der Fall ist, wird eine Exception geworfen. Das alles ist sehr grob und vereinfacht, aber es soll aufzeigen, dass man mit der Verwendung von Eigenschaften die vollständige Kontrolle über das Geschehen bekommt.

Read-only properties

Die meisten Eigenschaften, die du in diesem Tutorial sehen wirst, können sowohl gelesen als auch überschrieben werden, da dies die häufigsten Verwendungen von Eigenschaften sind. Aber das muss nicht immer so sein. Du kannst eine Eigenschaft auch erstmal nur mit einer get-Methode deklarieren, etwa so:

private string _name = "John Doe";

public string Name
{
	get { return _name; }
}

In diesem Fall kann die Eigenschaft "Namen" nicht mehr verändert werden, sie kann nur mehr gelesen werden und der Compiler wird eine Fehlermeldung werfen, wenn versucht wird, einen Wert zuzuweisen. Allerdings kann der Wert immer noch von innerhalb der Klasse verändert werden, denn hier (innerhalb der Klasse) kann man dem zugrundeliegenden Feld "_name" einfach einen neuen Wert zuweisen. Allerdings übergeht man damit gewissermaßen einen der größten Vorteile von Eigenschaften: Die Fähigkeit, jederzeit die Kontrolle darüber zu behalten ob ein wert akzeptiert wird. Wie wir bereits besprochen haben, ist die setter-Methode eine großartige Möglichkeit die Validierung (Gültigkeitsprüfung bzw. Plausibilitätsprüfung) des Wertes durchzuführen, aber wenn dem Feld "_name" von verschiedenen Orten ein neuer Wert zugewiesen wird, weil die Eigenschaft eigentlich nur dem lesenden Zugriff vorbehalten ist, kommt es nicht mehr zu dieser Validierung (sie wird umgangen).

Glücklicherweise bietet uns c# eine Lösung dafür: Man kann eine setter - Methode definieren, aber deren Sichtbarkeit limitieren, beispielsweise durch Verwendung der Schlüsselwörter private oder protected. Damit bekommt man das beste von beiden Welten: Einerseits hat man weiterhin die Möglichkeit, der Eigenschaft von innerhalb der Klasse Werte zuzuweisen (oder auch von jeder abgeleiteten Klasse, wenn das Schlüsselwort protected verwendet wurde), andererseits wird dieses auch entsprechend geprüft bzw. validiert. Das folgende Beispiel illustriert dies:

private string _name = "John Doe";

public string Name
{
	get { return _name; }

	private set
	{
		if(IsValidName(value))
			this._name = value;
	}
}

public bool IsValidName(string name)
{
	return name.EndsWith("Doe");

}

Der wesentliche Unterschied hier ist einfach das Schlüsselwort "private" direkt vor dem Schlüsselwort "set", und wie bereits erwähnt, kann dieses auch - je nach Bedarf - z.B. durch protected oder internal ersetzt werden.

Automatisch implementierte Eigenschaften

In manchen Fällen benötigt man nicht die gesamte Kontrolle über ein Feld, und es kann sich als umständlich erweisen, sowohl ein Feld als auch eine Eigenschaft zu implementieren, wobei die get- und set-Methoden nichts anderes tun als das, was wir im ersten Beispiel gesehen haben. Man könnte versucht sein, die Variable einfach als öffentliches Feld zu deklarieren, um all diesen zusätzlichen Aufwand zu vermeiden. Tue das bitte nicht! Zum Glück für uns alle hat Microsoft beschlossen, in C# Version 3 automatisch implementierte Eigenschaften hinzuzufügen, was einige Zeilen Code erspart. Sehen wir uns einfach den Unterschied an:

Reguläre Eigenschaft mit deklariertem Hintergrund-Feld:

private string _name;

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Hier das exakt identische Verhalten, aber als automatisch implementierte Eigenschaft:

public string Name { get; set; }

Beachte, dass die get- und set-Methoden leer sind und dass kein damit verbundenes privates Feld deklariert ist - mit anderen Worten, wir können jetzt genau dasselbe Verhalten wie im ersten Beispiel erreichen, aber mit einer einzigen Zeile Code! Man beachte, dass das private Hintergrund-Feld trotzdem zur Laufzeit vorhanden ist - es wird vom Compiler automatisch implementiert, wie der Name schon sagt. Stellt sich später heraus, dass man mehr Kontrolle über diese spezifische Eigenschaft benötigt, kann man sie einfach in eine reguläre Feld/Eigenschafts-Kombination mit der gewünschten Implementierung der get- und set-Methoden ändern.

Beachte, dass auch bei der Verwendung von automatisch implementierten Eigenschaften ein wichtiger Mechanismus zur Steuerung wie bei regulären Eigenschaften vorhanden ist: du kannst das Schlüsselwort set weglassen, um eine schreibgeschützte Eigenschaft zu erstellen, z. B. wie folgt:

public string ReadOnlyProperty { get; }

Es ist nicht erlaubt, automatisch implementierte Eigenschaften zu erstellen, auf die nur geschrieben werden kann.

Auto-implemented properties with default values

Prior to C# version 6, you could not define a default value for an auto-implemented property - for that, you would need a declared backing field, which would allow you to initialize the variable with a value:

private string _name = "John Doe";

public string Name
{
	get { return _name; }
	set { _name = value; }
}

But in C# version 6, Microsoft finally added the ability to initialize an auto-implemented property with a default value, like this:

public string Name { get; set; } = "John Doe";

Expression-bodied properties

Another property-related feature Microsoft implemented in C# 6.0 and 7.0 is the expression bodied members. It simply allows you to write single-line expressions for your properties and methods - in this case, let's look at how to use it for your get/set methods in a way that takes up less space and requires slightly less typing:

private string name;
public string Name
{
	get => name;
	set => name = value;
}

If your property is read-only, the syntax can be even shorter:

public string Name => "John Doe";

Of course this also works if you need to actually do something before returning the value, like this:

public string Name { get; set; } = "John Doe";

public string FirstName => this.Name.Substring(0, this.Name.IndexOf(" "));

As you can see, this allows you to define a get method but without the actual get and return keywords, while encouraging you to keep it all in one line instead of multiple lines.

Zusammenfassung

Eigenschaften (properties) geben uns mehr Kontrolle darüber, wie auf ein Feld zugegriffen und wie es manipuliert werden kann. Sie sollten immer dann verwendet werden, wenn der Zugriff von außerhalb der sie deklarierenden Klasse erfolgen soll.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!
Table of Contents