"??" Operator in C#
In meinem Beitrag zu NULL für Werttypen in C# hatte ich bereits beschrieben, wie man Werttypen in C# (z. B.
Nun kann es hin und wieder (z. B. zur Arbeit mit externen Bibliotheken) jedoch notwendig sein, diesen Wert einer Variable grundsätzlich gleichen Typs zuzuweisen, die jedoch kein
Im Übrigen funktioniert das mit beliebigen Referenztypen (deren Wert schließlich immer
bool
, int
) indirekt dazu bewegen kann, auch null
zu akzeptieren, was ansonsten ja nicht möglich ist.Nun kann es hin und wieder (z. B. zur Arbeit mit externen Bibliotheken) jedoch notwendig sein, diesen Wert einer Variable grundsätzlich gleichen Typs zuzuweisen, die jedoch kein
null
akzeptiert. Behelfen kann man sich in derartigen Fällen selbstverständlich mit Konstrukten wie diesem:
Zuweisung ohne
Etwas kompakter geht es jedoch mit dem ??
-Operator
010203040506
bool? isValid = null;
bool isRealValid = false;if(isValid.HasValue) { isRealValid = isValid.Value;} // "isRealValid" enthält "false", wenn "isValid" (ebenfalls) "false" oder "null" ist
??
-Operator (nicht zu verwechseln mit dem ternären ?:
-Operator):
Zuweisung mit
Der Wert hinter dem Operator dient also als Ersatzwert für ??
-Operator
01020304
bool? isValid = null;
bool isRealValid = isValid ?? false;// "isRealValid" enthält "false", wenn "isValid" (ebenfalls) "false" oder "null" ist
null
. In beiden Fällen gilt jedoch zu beachten, dass die ursprüngliche Semantik nicht erhalten bleibt. Einem reinen Werttyp kann nun einmal kein null
zugewiesen werden, d. h. man muss sich für diesen Fall einen angemessenen Ersatz (z. B. -1
für int
) suchen.Im Übrigen funktioniert das mit beliebigen Referenztypen (deren Wert schließlich immer
null
sein darf), womit sich beispielsweise bequem Standardobjekte zuweisen lassen:
Multidimensional and Jagged Arrays in C#
Eindimensionale Felder in C# sind schnell eingeführt und verwendet, dazu hatte ich auch schon einmal etwas im Zusammenhang mit PHP geschrieben. Bei den weiteren Varianten des Arrays in C# kann man grundsätzlich zwischen zwei Möglichkeiten unterscheiden: Mehrdimensionale und Verzweigte ("Array von Arrays"). Wir möchten uns daher beide einmal näher ansehen und beginnen zuerst mit dem mehrdimensionalen Feld:
Wir können anschließend wie folgt damit arbeiten:
Mehrdimensionales Feld
Während es sich bei eindimensionalen Feldern mathematisch betrachtet um Vektoren handelt, handelt es sich hierbei um eine m*n-Matrix (mit 3 Zeilen und 5 Spalten); analog dazu wären auch dreidimensionale Gebilde etc. möglich. Wichtig zu erkennen ist an dieser Stelle, dass es sich tatsächlich um eine rechteckige Anordnung (nicht jedoch zwangsläufig um eine quadratische) handelt, d. h. jede Zeile besitzt gleich viele Spalten.0102030405
int[,] matrix = new int[,] { {11,12,13,14,15}, {21,22,23,24,25}, {31,32,33,34,35}};
Wir können anschließend wie folgt damit arbeiten:
Elemente durchlaufen
Eine weitere Möglichkeit sind nun die sog. verzweigten Felder:
0102030405060708091011121314151617181920212223242526272829
// Verschachtelte Schleifenfor(int m = 0; m < 3; m++) { // Zeilen for(int n = 0; n < 5; n++) { // Spalten /** * matrix[m, n] enthält das * entsprechende Element. **/ }}
// Einfache Schleifefor(int i = 0; i < matrix.Length; i++) { // matrix.Length = (3 * 5) /** * matrix[i / 5, i % 5] enthält * das entsprechende Element. * * C++-Entwickler mögen an dieser Stelle * an *(*matrix + i) denken, was man bei * C# jedoch nur "unsafe" bekommt. **/}
// FOREACH-Schleifeforeach(int x in matrix) { /** * "x" enthält nun das * entsprechende Element. **/}
Verzweigtes Feld
Bereits die Initialisierung verdeutlicht sehr gut, dass es sich wie bereits erwähnt um ein Array von Arrays handelt, wobei jeder Eintrag nun ein Feld "beliebiger" Länge sein kann. Beim Durchlaufen – diesmal im Allgemeinen natürlich nur noch mit verschachtelten Schleifen möglich – wird dies noch einmal dadurch betont, dass wir die entsprechende 0102030405
int[][] data = new int[][] { new int[] {11,12,13}, new int[] {21,22,23,24}, new int[] {31,32,33,34,35}};
Length
-Eigenschaft (auch) für die innere Schleife nutzen können (und werden):
Elemente durchlaufen
Derartige Felder werden übrigens oft auch "jagged array" genannt. Zuletzt sei noch erwähnt, dass sich beide Formen durchaus auch kombinieren lassen. Weitere Informationen und Beispiele gibt es wie üblich im MSDN. 01020304050607080910111213141516171819
// FOR-Schleifenfor(int i = 0; i < data.Length; i++) { for(int j = 0; j < data[i].Length; j++) { /** * data[i][j] enthält das * entsprechende Element. **/ }}
// FOREACH-Schleifenforeach(int[] i in data) { foreach(int j in i) { /** * "j" enthält nun das * entsprechende Element. **/ }}
Reverse Numbers without Converting
Passend zu einem etwas älteren Beitrag zur Ermittlung der Anzahl der Ziffern einer Zahl soll es noch einmal darum gehen, ein Problem mathematisch zu lösen, statt den Umweg über Zeichenketten zu gehen. Konkret möchten wir eine Zahl schlicht "umdrehen". Im Prinzip soweit natürlich kein Problem:
Das funktioniert – zumindest bei nicht-negativen Zahlen – soweit auch einwandfrei und kann je nach Kontext auch die schnellste Variante sein, jedoch lässt sich das Problem auch rein rechnerisch lösen:
Zahl umdrehen (mit Konvertierung)
Wir konvertieren die Zahl hierbei zuerst zu einer Zeichenkette, drehen die Zeichen anschließend um und fügen sie zusammen, um sie letztlich wieder zu einer Zahl zu konvertieren.010203
int number = 12345;
int numberReverse = Int32.Parse(String.Concat(number.ToString().Reverse())); // 54321
Das funktioniert – zumindest bei nicht-negativen Zahlen – soweit auch einwandfrei und kann je nach Kontext auch die schnellste Variante sein, jedoch lässt sich das Problem auch rein rechnerisch lösen:
Zahl umdrehen (ohne Konvertierung)
Wir nutzen dabei aus, dass uns der Modulo-Operator (010203040506070809
int number = 12345;
int numberReverse = 0;while(number != 0) { numberReverse *= 10; numberReverse += (number % 10);
number /= 10;} // "numberReverse" enthält nun (ebenfalls) 54321
%
) jeweils den Rest einer ganzzahligen Division liefert, welchen wir als neue Ziffer der Lösung verwenden und anschließend die gegebene Zahl um eben diesen Anteil verringern. Als netter "Nebeneffekt" funktioniert diese Vorgehensweise auch bei negativen Zahlen problemlos. Alphabetical Index with C# and LINQ
Häufig kann es sinnvoll sein, eine Liste nach Anfangsbuchstaben gruppiert darzustellen. Dies kann unter C# in Verbindung mit LINQ sehr einfach und elegant geschehen, wozu wir wie üblich ein kleines Beispiel durchgehen.
Konkret möchten wir
Konkret möchten wir
Person
en nach Anfangsbuchstabe von LastName
gruppiert und darin wiederum nach LastName
sortiert ausgeben. Auf Grund der Trivialität der Klasse verweise ich auf das im Artikel zu Eigenschaften in C# präsentierte Beispiel und fahre direkt mit der Liste fort:
Liste von Personen
Nun führen wir die Gruppierung ganz einfach per 01020304050607080910111213141516171819202122
List<Person> personList = new List<Person>() { new Person() { FirstName = "Harald", LastName = "Müller" }, new Person() { FirstName = "Helga", LastName = "Schmidt" }, new Person() { FirstName = "Karl", LastName = "Schneider" }, new Person() { FirstName = "Olaf", LastName = "Fischer" }, new Person() { FirstName = "Saskia", LastName = "Weber" }};
GroupBy(…)
aus und speichern dies mit den dazugehörigen Listen per ToDictionary(…)
direkt in ein Dictionary
:
Liste gruppiert abspeichern
Anschließend können wir die Struktur beispielsweise durchlaufen und auf einer Webpräsenz ausgeben:
010203
Dictionary<char, List<Person>> personStructure = personList .GroupBy(p => p.LastName[0]) // Gruppierung nach erstem Buchstaben des Nachnamens .ToDictionary(k => k.Key, v => v.ToList());
Struktur durchlaufen
Das Ergebnis einer solchen Vorgehensweise lässt sich u. a. in der neuen Ansicht der Bezirkszuordnungen auf meinem Städteportal für Berlin und Hamburg betrachten. Für diese einfache Darstellung kommt übrigens noch ein zusätzlicher kleiner LINQ-"Trick" mit 01020304050607080910
foreach(KeyValuePair<char, List<Person>> data in personStructure) { // "data.Key" enthält den Anfangsbuchstaben
foreach(Person person in data.Value.OrderBy(p => p.LastName)) { /** * "person" enthält nun jeweils eine zu eben * diesem Anfangsbuchstaben passende Person. **/ }}
Select(…)
zum Einsatz. Für unser Beispiel könnten wir dazu die innere Schleife schlicht durch Folgendes ersetzen und damit Vor- und Nachname per Komma separiert ausgeben:
Einfache Zeichenketten-Konkatenierung
01
String.Join(", ", data.Value.Select(p => p.FirstName + " " + p.LastName));
City Portal extended
In letzter Zeit war es hier etwas ruhiger im Blog. Das liegt einerseits daran, dass ich beruflich recht eingespannt bin und andererseits daran, dass ich ein den meisten regelmäßigen Besuchern dieser Webpräsenz sicherlich bereits bekanntes Projekt stark erweitert habe: Mein Portal für die beiden Stadtstaaten Berlin und Hamburg.
Ich erlaube mir demnach eine kleine zusätzliche Werbung dafür und fasse ein paar Neuerungen kurz zusammen:
Für Interessierte sei zum Schluss auch noch erwähnt, dass das gesamte Portal ebenso wie diese Webpräsenz hier auf ASP.NET MVC mit C# basiert. Der Zugriff auf die Datenbank erfolgt per ADO.NET Entity Framework mit LINQ.
Ich erlaube mir demnach eine kleine zusätzliche Werbung dafür und fasse ein paar Neuerungen kurz zusammen:
- Bahnhöfe besitzen nun die Information,
- ob sie sich ober-/unterirdisch befinden,
- in welchem Tarifbereich sie sich befinden
- und ob sie barrierefrei erreichbar sind.
- Einige dutzend Bezirkszuordnungen wurden erfasst oder präzisiert.
- Über hundert neue Geo-Koordinaten wurden erfasst und mehrere dutzend Wikipedia-Artikel ergänzt.
- Es können Entfernungsberechnungen auf Basis der Koordinaten (per Orthodrome) durchgeführt werden.
- Es existieren jeweils zusätzlich separate RSS-Feeds für Berlin und Hamburg.
- Es existiert ein (Veranstaltungs-)Kalender mit Feiertagen.
- Es existiert ein neuer Abschnitt für Parkanlagen.
- Es existiert ein neuer Abschnitt für das aktuelle Wetter mit Vorhersage (per wetter.com).
Für Interessierte sei zum Schluss auch noch erwähnt, dass das gesamte Portal ebenso wie diese Webpräsenz hier auf ASP.NET MVC mit C# basiert. Der Zugriff auf die Datenbank erfolgt per ADO.NET Entity Framework mit LINQ.
Project links
-
BitStadt – Stadtportal
Berlin · Hamburg · Amsterdam -
CCC – Fahrplan
Schedules for the CCCongress
Categories / Archive | Übersicht
- PHP functions in C# (136)
- Dictionary (257)
Tags
.NET · ADO.NET · Work · ASP.NET MVC · Blog · C# · Generics · Society · Computer Science · Java · LINQ · Logic · Mathematics · Network · PHP · Project · Security · Software development · Studies · Technics · Theory · Web design · WPF