Optionale und benannte Parameter in C# 👍 👎

Wie viele andere Programmiersprachen (z. B. PHP) unterstützt auch C# seit einiger Zeit optionale Parameter. Die Verwendung ist denkbar einfach:
Optionale Parameter
01020304050607080910
  // Kreisfläche berechnenpublic double GetCircleArea(double radius = 1) {    return (Math.PI * (radius * radius));}

double circleArea = GetCircleArea(5); // Kreisfläche für Radius "5"
double circleArea = GetCircleArea(1); // Kreisfläche für Radius "1"double circleArea = GetCircleArea(); // Kreisfläche für Radius "1"
Der beim letzten Aufruf weggelassene Parameterwert wird dabei implizit durch die Zuweisung des Standardwertes der Definition (radius = 1) gesetzt, um den Flächeninhalt des Einheitskreises zu erhalten. Aus naheliegenden Gründen sind optionale Parameter hinter nicht-optionalen Parametern zu definieren. Ein ähnliches Verhalten lässt sich selbstverständlich auch durch das Überladen der Methode erreichen, was jedoch etwas aufwändiger ist und zumindest in unserem Beispiel nicht ganz so intuitiv erscheint:
Optionale Parameter (per Methodenüberladung)
0102030405060708
  // Kreisfläche berechnenpublic double GetCircleArea(double radius) {    return (Math.PI * (radius * radius));}
public double GetCircleArea() { return this.GetCircleArea(1);}
Der Aufruf kann nun jeweils analog zu unserem vorherigen Beispiel erfolgen.

Darüber hinaus unterstützt C# jedoch auch benannte Parameter. Damit ist es nicht notwendig, die korrekte Position eines Parameters zu verwenden; diese werden stattdessen über ihren Namen angesprochen, was insbesondere im Zusammenhang mit (mehreren) optionalen Parametern sinnvoll sein kann:
Benannte Parameter
0102030405060708091011
  // Flächeninhalt berechnenpublic double GetArea(double height = 1, double width = 1) {    return (height * width);}

double area = GetArea(); // Höhe: 1, Breite: 1double area = GetArea(2); // Höhe: 2, Breite: 1double area = GetArea(3,4); // Höhe: 3, Breite: 4
double area = GetArea(width: 5); // Höhe: 1, Breite: 5 (benannter Parameter)
Es genügt dazu also, ganz einfach den Namen des Parameters, gefolgt von einem ":" (Doppelpunkt) und dem Wert anzugeben. Zu beachten gilt, dass benannte Parameter zwar auf per Position festgelegte Parameter folgen können, der umgekehrte Fall jedoch nicht unterstützt wird.

Index-basierter Zugriff auf Objekte in C# (und PHP) 👍 👎

Manchmal kann es sinnvoll (oder zumindest bequem oder intuitiv) sein, auf ein Objekt im Stile eines Feldes zugreifen zu können. Für das folgende Beispiel zu diesem Thema möchte ich kurz einen Anwendungsfall aus meiner Arbeit beschreiben.

Als ISP müssen wir bei Domains des Öfteren mit sog. "Handles" umgehen. Grob umrissen handelt es sich dabei um einen Kontakt-Datensatz für eine Domain. Darin abgelegt werden beispielsweise der Name, die Anschrift und – je nach TLD – auch noch div. andere Daten.

Im einfachsten Fall verwendet man zur Ablage dieser Informationen also ein assoziatives Feld (in C# z. B. ein generisches Dictionary) als Eigenschaft des Objekts:
"Handle"-Klasse
010203040506
public class Handle {    public Dictionary<string,string> HandleFieldValueList  {        get;        set;    }}
Den Umgang mit derartigen Datenfeldern habe ich zwar schon einmal relativ ausführlich beschrieben, dennoch möchten wir auch hier erst einmal das Objekt mit Daten füllen:
Daten hinzufügen
010203040506070809
Handle ich = new Handle() {      // Feldwerte    HandleFieldValueList = new Dictionary<string,string>() {        {"firstName", "Holger"},        {"lastName", "Stehle"}    }};
// ich.HandleFieldValueList["firstName"] enthält "Holger" etc.
Wie bereits angedeutet, können wir nun wie erwartet auf die entsprechenden Daten zugreifen. In einem solchen Fall – in dem die einzelnen Werte schließlich das Handle an sich ausmachen – wäre es doch aber auch praktisch, diesen Index-basierten Zugriff direkt auf dem Objekt durchführen zu können. Und genau dies ist mit C# ganz einfach möglich. Dazu müssen wir die Klasse wie folgt erweitern:
Indexer ergänzen
01020304050607080910111213141516171819
public class Handle {      // Indexer (-> Feldwerte)    public string this[string fieldName] {        get {            return this.HandleFieldValueList[fieldName];        }        set {            this.HandleFieldValueList[fieldName] = value;        }    }
// Feldwerte public Dictionary<string,string> HandleFieldValueList { get; set; }}
// ich["firstName"] enthält "Holger" etc.
Dies veranschaulicht die Implementierung eines sog. Indexers, welcher sich grundlegend wie eine Eigenschaft verhält. Der hauptsächlich interessante Teil string this[string fieldName] besagt, dass ein Index-basierter Zugriff auf die Instanz (→ this) mit einem Index (→ fieldName) des Typs string einen string liefert und definiert im Stile eines Akzessors, wie genau dies geschieht. Und schon können wir (wie im Code angedeutet) wie erhofft darauf zugreifen.

Indexer können auch überladen werden, so dass z. B. zusätzlich auch ein Zugriff mit numerischem Index ermöglicht werden kann. Zuletzt gilt zu beachten: Es handelt sich hierbei lediglich um eine etwas kompaktere Schreibweise für etwas, was sowieso möglich wäre. Dennoch gibt es – wie ich persönlich finde – interessante Einsatzmöglichkeiten hierfür. Der konkrete Nutzen ist also im Einzelfall abzuwägen.

Um derartiges Verhalten in PHP zu ermöglichen, muss die Klasse die Schnittstelle ArrayAccess implementieren. Ein Beispiel zur Umsetzung findet sich z. B. in der offiziellen Dokumentation.

Partielle Klassen in C# 👍 👎

C# unterstützt sogenannte partielle Klassen, welche es ermöglichen, eine Klasse auf verschiedene Dateien verteilt zu definieren. Diese werden bei der Kompilierung zu einer einzelnen Klasse zusammengeführt, so als wäre sie wie eine "normale" Klasse in einer Datei definiert worden. Insbesondere ist also auch dateiübergreifend Zugriff auf private Mitglieder (Eigenschaften, Methoden etc.) einer Klasse möglich.

Wir wollen dies wie üblich an einem (kleinen) Beispiel konkretisieren und legen dazu einfach die Eigenschaften und Methoden einer Klasse in zwei verschiedenen Dateien ab:
Klasse "Person" in Datei "Person.cs"
01020304050607080910111213141516
public partial class Person {    public Person(string firstName, string lastName) {        this.FirstName = firstName;        this.LastName = lastName;    }
// Partner liefern public Person GetPartner() { // z. B. aus Datenbank auslesen }
// Kinder liefern public List<Person> GetChildren() { // z. B. aus Datenbank auslesen }}
Klasse "Person" in Datei "Person.Properties.cs"
01020304050607080910111213141516
public partial class Person {    public string FirstName {        get;        set;    }
public string LastName { get; set; }
public int Age { get; set; }}
Zugegeben: Es ist fraglich, ob dieses Vorgehen – insbesondere in diesem trivialen Beispiel – überhaupt sinnvoll ist. Andererseits ergibt sich für den Aufrufer/Verwender der Klasse keinerlei Unterschied zur Definition in einer Datei, da letztlich eine einzige Klasse herauskommt. Insofern ist dem Entwickler (bzw. den Richtlinien des Teams) überlassen, ob und ggf. wie man damit umgehen möchte. Die Verwendung erfolgt jedenfalls ganz wie gewohnt:
Anwendung der partiell definierten Klasse
010203
Person ich = new Person("Holger", "Stehle") {    Age = 24};
Ein großer Vorteil ergibt sich jedoch bei der Verwendung von Code-Generatoren. Der generierte Code definiert dabei partielle Klassen. Diese können nun in einer eigenen Datei erweitert werden, ohne Gefahr zu laufen, bei einer neuen automatischen Codegenerierung alle Anpassungen zu verlieren. Visual Studio selbst setzt auf derartiges Vorgehen z. B. im Zusammenhang mit ADO.NET Entity Framework oder grafischen Benutzeroberflächen (vgl. "*.Designer.cs"-Dateien).

Andere Einsatzmöglichkeiten wären die übersichtliche Arbeit verschiedener Entwickler an einer umfangreicheren Klasse oder das Anbieten einer Anwendung mit verschiedenen Ausprägungen der Funktionalität einer Klasse, indem nur spezifische Dateien der partiellen Klasse kompiliert werden.

Mit der praktischen kleinen Erweiterung NestIn für Visual Studio (nicht Express) könnt ihr im Übrigen mit wenigen Mausklicks auch dafür sorgen, dass die Dateien wie aus der Entwicklungsumgebung bekannt verschachtelt dargestellt werden, was meiner Ansicht nach deutlich zur Übersicht beiträgt.

Galerie 👍 👎

Ich habe eine kleine Galerie gestartet, die unregelmäßig erweitert werden soll.

Schlagworte und Suche 👍 👎

Ab sofort findet ihr hier im Blog Schlagworte zu den einzelnen Beiträgen.

Darüber hinaus können die Beiträge nun auch bequem durchsucht werden.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche