{the magic lies between the brackets}

Schlagwort: LINQ (Seite 1 von 1)

[C#] XML in Applikation einlesen

Um schnell mal eine XML-Datei in die Applikation einzulesen, bedarf es dank des .NET-Frameworks nicht viel Arbeit.

Ich nutze dazu die XDocument-Klasse mit welcher es möglich ist XML zu parsen und zu schreiben.

Mein XML hatte folgende Form:

<?xml version="1.0" encoding="utf-8" ?>
<Phonenumbers>
  <phonenumber>
    <Name>Test</Name>
    <Number>12345678</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test2</Name>
    <Number>11111111</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test3</Name>
    <Number>222222222</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test4</Name>
    <Number>333333333</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test5</Name>
    <Number>44444444444</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test6</Name>
    <Number>55555555555</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test7</Name>
    <Number>66666666666</Number>
  </phonenumber>
  <phonenumber>
    <Name>Test8</Name>
    <Number>77777777777</Number>
  </phonenumber>
</Phonenumbers>

In die Applikation wird das XML mit folgendem Code geladen:

string xml = System.IO.File.ReadAllText(PfadZurXMLDatei);
XDocument xmlReader =  XDocument.Parse(xml);
var List = from element in xmlReader.Descendants("phonenumber")
		select new
		{
			name = (string)element.Element("Name"),
			number = (string)element.Element("Number"),
			//Weitere Elemente lesen
		};
foreach (var item in List)
{
	listBox1.Items.Add(item.name);
	listBox2.Items.Add(item.number);
}

[C#/.NET] – Liste in mehrere Listen splitten/gruppieren

Mein Problem war es zu Beginn eines früheren Projektes eine List<T> (in meinem Fall List<Reporter>) in mehrere Unterlisten zu sortieren.
Meine Klasse sah grob so aus:

     class Reporter
    {
        public string name;
        public string birthYear;

        public Reporter(string birthYear, string name)
        {
            this.name = name;
            this.birthYear = birthYear;
        }
    }

Meine Liste bestand aus mehreren Reportern und sah so aus:

Birthyear Name

  • 1991 Jon
  • 1992 Dominic
  • 1993 Jack
  • 1994 Hillary
  • 1991 Jackson
  • 1994 Jaqueline

Nun wollte ich die Liste in mehrere Listen splitten und zwar je nach Geburtsjahr:

Birthyear Name


1991 Jon

1991 Jackson


1993 Jack


1992 Dominic


1994 Hillary

1994 Jaqueline


Das Ergebnis erreichte ich relativ einfach mit einem Einzeiler:
Zuerst gruppierte ich die Liste mit einer Lambda-Expression nach dem Geburtsjahr:

 var groups = reporterList.GroupBy(x => x.birthYear); 

Danach wählte ich jede Gruppe aus (Lambda) und konvertierte jedes Element in eine Liste:

 var groups = groups.Select(grp => grp.ToList()); 

Und schlussendlich fügte ich alle Gruppen in eine Liste zusammen:

 var groups = groups.ToList(); 

Ein Einzeiler, der all das macht, ist einfach eine Aneinanderreihung dieser Befehle:

 var groups = reporterList.GroupBy(x => x.birthYear).Select(grp => grp.ToList()).ToList(); 

Und voíla hat man eine Liste aller Gruppen.

[C#/.NET] – Lambda Expressions in LINQ Queries

Genauso wie LINQ wurden auch Lambda Expressions in C# mit dem .NET Framework 3.5 eingeführt.
Diese haben viele Vorteile. Unter anderem haben sie den Syntax von anonymen Methoden vereinfacht und bieten eine flexiblere Nutzung. Des weiteren können sie genutzt werden um LINQ Abfragen auszuführen.

Beispiel:

 IEnumerable query = from names in nameList where names.forename[0].ToString().ToLower() == "s" select names; 

Ich frage hier ganz einfach ab, welcher Vorname in der List mit einem s beginnt (unabhängig von Groß-/Kleinschreibung).
Schneller und schöner geht es mit Lambda Ausdrücken:
Wir benötigen wieder ein IEnumerable als „Platz“ für unsere gefundenen Einträge.

  IEnumerable v = nameList.Where(name => name[0].ToString().ToLower() == "s"); 

Jetzt fragen wir ab, wo(Where) sich (in der List nameList) Einträge befinden, die mit einem s beginnen (auch hier unabhängig von der Orthografie).

Der => (Operator Lambda) wird genutzt um die Eingangsvariable (name) vom Lambdaausdruck zu trennen

[C#/.NET] – Einführung in LINQ – SQL für Objekte

Seit einiger Zeit ging es in meinen Projekten immer mehr um gute Lesbarkeit des Codes, da die Wartbarkeit der Projekte wichtig war.
Oftmals musste ich in Listen wühlen und bestimmte Items (<T>) bzw. Indices herausfinden.
Früher tat ich das in einfachen for/foreach-schleifen und einer if-Abfrage:

    foreach (Person item in myList)
   {
      if (item.Age == 20)
      {
          n = myList.IndexOf(item);
          break;
      }
   }    

Codemäßig ist dies aber wirklich – nennen wir es mal suboptimal gelöst. (Klar können wir alles gruppieren etc…)

Auf der Suche nach einem besseren Weg meine Arrays und Listen zu durchlaufen fand ich schließlich LINQ im Namespace System.LINQ.

LINQ ist erst ab .NET 3.5 verfügbar, wer LINQ davor nutzen will, kann LINQBridge nutzen, ein Framework, welches alle Standardqueryoperatorionen in .NET Framework 3.5’s Enumerable Klasse reimplementiert.

Ich werde hier nur auf die Query Expressions eingehen. Man kann aber auch Lambda Expressions nutzen, dazu aber ein anderes Mal mehr.

Nun verwenden wir also den Namespace mit der using-Direktive:

 using System.LINQ; 

Vorweg: SQL Wissen ist hier sehr praktisch!

Warum seht ihr hier:

             IEnumerable myQuery =  from m in myFiles
                                    select m.extension; 

Syntaktisch ist LINQ sehr an SQL angelehnt, es wird spezifiert von was die Daten kommen (from) und was ausgegeben wird (select).

In unserem Beispiel habe ich also eine List myFiles und frage das Attribut extension des Objektes T in der Liste ab.

Der Typ IEnumerable muss hier genutzt werden, denn:
   1. Die Abfrage hat als Quelle eine Liste, welche IEnumerable implementiert.
   2. Die Abfrage selbst gibt ein IEnumerable zurück.

Wenn man faul ist, kann man auch implizit deklarieren, mit var.
Der Compiler führt dann die explizite Deklaration durch.

Wer sich in SQL auskennt wird sich jetzt sicher fragen, wie es mit Bedingungen aussieht.
Klar, die gibt es auch. Sonst wäre LINQ wirklich nutzlos:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    select m.extension; 

Hier ist zu beachten, dass immer noch der C#-Syntax gilt – also Vergleichsoperatoren von C# nutzen!

Zudem gibt es natürlich auch Gruppier- und Ordnungsfunktionen:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    orderby m.extension
                                    select m.extension; 

Hier wird also zusätzlich noch alphabetisch geordnet. Ascending/Descending sind natürlich verfügbar.

  orderby m.extension ascending 
  orderby m.extension descending 

Zu guter letzt hat Microsoft auch hier ein tolles Feature aus SQL übernommen, nämlich Joins.
Vom Grundprinzip ist es wieder SQL gleich:

 join "Objekthier" on "Key1" equals "Objekthier.Key2" 

Beispiel:

 join file in FileList on extension.Id equals file.Id 

Ein vollständiges LINQ-Query sieht also beispielweise so aus:

IEnumerable query = (from file in fileList
join ext in extensionList on file.Id equals ext.Id 
where ext.Id == 1 && file.ReadOnly == false
orderby ext.extension ascending
select file); 

Aber Achtung:

Das gejointe Objekt (file) muss sich auf der rechten Seite des equals-Statements befinden, ansonsten schmeißt der Compiler folgenden Fehler:

Name model is not in scope on the left side of equals. Consider swapping the expression on the either side of equals.

WARNUNG: LINQ ist bis zu zwei mal langsamer als for-Schleifen und dient nur zum Aufbau strukturierteren Codes. Meistens ist die Abfrage performancemäßig vergleichbar mit einer foreach-Schleife