Neues zu Roslyn und C#

Seite 3: Properties

Inhaltsverzeichnis

Eigenschaften oder Properties werden in C# gerne genutzt und lösen die Kombination aus Getter/Setter und privaten Feldern ab. Sogenannte "auto-properties" lassen sich sogar ganz ohne private Felder definieren. Der C#-Compiler erzeugt sie automatisch und wird dies in der kommenden Version auf für Properties tun. Der folgende Codeausschnitt zeigt dazu zwei Beispiele.

public class Customer
{
public string Firstname { get; set; } = "Fabian";
public string Lastname { get; set; } = "Deitelhoff";
}

public class Customer
{
public string Firstname { get; } = "Fabian";
public string Lastname { get; } = "Deitelhoff";
}

In der oberen Klasse werden zwei "auto-property"-Objekte direkt mit zwei Zeichenketten initialisiert. Da die Initialisierung nun möglich ist, fällt es deutlich einfacher, eine Klasse vollständig als immutable zu definieren. Früher ging das nur mit Read-only-Feldern und privaten Settern, wobei bei letzteren Properties über einen Konstruktor zu setzen waren. In beiden Fällen war allerdings mehr notwendig als die reine Property, sodass der Vorteil etwas gemindert wurde. Mit einer "getter-only"-Property und direkter Initialisierung ist das nun einfacher zu erreichen, was viel Code einsparen kann.

Das nächste Sprachfeature adressiert den Umstand, dass Konstruktoren, die Parameter für Eigenschaften enthalten, innerhalb einer Klasse zu deklarieren sind. Das folgende Beispiel zeigt dazu eine Klasse mit einem primären Konstruktor:

public class Customer(string firstName, string lastName)
{
public string Firstname { get; } = firstName;
public string Lastname { get; } = lastName;
}

Die Klassendefinition bekommt direkt beide Parameter mitgegeben, die wiederum bei der Initialisierung der beiden "auto-properties" zum Einsatz kommen. Der gleiche Effekt lässt sich bisher nur über zwei private Felder realisieren, denen Entwickler die Parameter eines eigens definierten Konstruktors übergeben können. Ein Knackpunkt dieses Beispiels sind die beiden Eigenschaften, die keinen Setter enthalten. Neben den Settern lassen sich auch die privaten Felder einsparen. Wie Eingangs erwähnt, ist das lediglich eine Verbesserung der Syntax.

Im übrigen funktioniert das neue Verhalten auch mit privaten Feldern, die man direkt in der Klassendefinition mit angeben kann:

public class Customer(string firstName, string lastName, 
private int age)
{
public string Firstname { get; } = firstName;
public string Lastname { get; } = lastName;
}

Das private Feld age kann in der Klasse Customer an beliebigen Stellen zum Einsatz kommen.

Die nächste Funktion ist, aus Sicht des Schreib- und Leseaufwands, sicherlich zu begrüßen, dennoch ist sie nicht unumstritten: Es geht um den Einsatz von statischen Klassen beziehungsweise deren statischen Methoden und die Verwendung von using-Anweisungen. Im folgenden ist ein typischer Code-Ausschnitt zu sehen.

using System.Console;
using System.Math;

private class Program
{
static void Main()
{
WriteLine(Pow(2, 4));
}
}

Mit ihm soll das Programm das Ergebnis von 2 hoch 4 berechnen und es im Anschluss direkt auf der Konsole ausgeben. Allerdings fehlen hier ganz offensichtlich die using-Anweisungen. Die Namensräume System.Console und System.Math werden direkt zu Anfang eingebunden. Das neue Sprachfeature sorgt dafür, dass alle statischen Member im Code ohne explizite Nennung des jeweiligen Namensraums zur Verfügung stehen. Das hört sich im ersten Moment vielleicht vorteilhaft an. Wird das Feature allerdings zu oft genutzt, insbesondere bei verschachtelten Aufrufen, kann es auch enorm dazu beitragen, dass unleserlicher Code entsteht. Das hat auch Microsoft erkannt und im aktuellen Dokument "Upcoming Features in CSharp" darauf hingewiesen.

Selbiges gilt für Erweiterungsmethoden, die bekanntlich nichts anders als statische Methoden sind – obwohl ihre Erfinder sie nicht dazu konzipierten, dass man sie wie solche nutzt. Hier wird es in zukünftigen Versionen von Roslyn Änderungen geben.

Die Option, Deklarationen direkt in Anweisungen durchführen zu können, ist eine sehr kleine Änderung in C#. Nichtsdestotrotz kann sie Code deutlich reduzieren – nicht unbedingt pro Anweisung, aber häufig macht es in dem Fall die Masse, wie der folgende Ausschnitt zeigt:

if (int.TryParse(s, out int index))
GetData(out var min, out var max);
Console.WriteLine("Ziel: {0}", (int target = CalculateTarget()) * distance);

Allen Fällen ist gemein, dass sich Variablen direkt innerhalb einer Methode beziehungsweise in der Anweisung deklarieren lassen. Bisher war es zwingend erforderlich, das schon vorher zu tun.

An Stellen, an denen var zum Einsatz kommt, wird der Typ durch Deklarationen ermittelt. Dazu dient beispielsweise eine Methodensignatur, in der out-Parameter eines bestimmten Typs vorhanden sind. Auch hier stellt sich die Frage, ob die Funktion das Ziel des Quelltextes verschleiert. Der übermäßige Einsatz des Features sollte daher wohl bedacht werden.