{the magic lies between the brackets}

Schlagwort: C (Seite 2 von 3)

[C#/.NET] – XML Deserialisierung von Objekten

Bezugnehmend auf die Serialisierung eines Objektes in C#, möchte man das gespeicherte Objekt in Form eines XML-Files sicher wieder laden können.
Auch hier bietet das .NET-Framework eine einfach Möglichkeit.

Der erste Schritt ist natürlich – wie immer – den Namespace einzubinden:

using System.Xml.Serialization;

Nun erstellt man ein Objekt vom Typ XmlSerializer und definieren, von welchem Typ die serialisierten Daten sind (hier: User )

XmlSerializer userDeserializer = new XmlSerializer(typeof(User)); 

Um die Datei nun einzulesen, benötigen wir einen StreamReader, wir erstellen also ein Objekt davon:

StreamReader reader = new StreamReader(@"C://xmlfile.xml"); //Parameter des Konstruktors ist hier der Pfad zur XML-Datei

Zur Erinnerung, die Datei sah so aus:

<?xml version="1.0" ?> 
  <User>
    <name>Fabian</name> 
    <index> 1 </index>
  </User> 

Nun brauchen wir noch ein Objekt vom Typ User, ich nenne das Objekt mal userFabian.

 User userFabian = new User(); 

Nun weisen wir diesem Objekt, die gespeicherten Werte via Deserialisierung des Files zu. Als Parameter des XMLSerializer übergeben wir das StreamReader-Objekt

 userFabian = (User)userDeserializer.Deserialize(reader); 

Ein Cast zum Typ des Objektes (User) ist, trotz der vorigen Angabe unerlässlich.

Anschließend schließen wir den StreamReader und das Objekt wurde erstellt.

reader.Close();

Fertig!

[C#/.NET] – Unterschied zwischen new virtual und override

Wer mit Vererbung arbeitet, hat sicher schon mit dem Begriff override zu tun gehabt.
Was es aber auch gibt ist das Schlüsselwort new bzw. virtual .
Wo ist der Unterschied?

Erstellen wir ein Beispiel. Wir haben eine Klasse mit der Bezeichnung Engineer:

     class Engineer
    {
        protected string name;
        protected double billingRate;

        public Engineer(string name, double billingRate)
        {
            this.name = name;
            this.billingRate = billingRate;
        }

        public virtual double calcMoney(double hours) //virtual ermöglicht das überschreiben der Methode in abgeleiteten Klassen
        {
            return billingRate * hours * 2.0d; //Standardfunktion, falls nicht überschrieben
        }

    }  

Hier haben wir die virtuelle* Methode calcMoney.

virtual: Mit dem virtual-Schlüsselwort kann eine Methode, eine Eigenschaft, ein Indexer oder eine Ereignisdeklaration geändert und in einer abgeleiteten Klasse überschrieben werden.

(Quelle: MSDN)

Nun erstellen wir eine Klasse CivilEngineer (Bauingenieur) und leiten von Engineer-Klasse ab:

     class CivilEngineer : Engineer
    {
        public CivilEngineer(string name, double billingRate)
            : base(name, billingRate)
        {
            this.name = name;
            this.billingRate = billingRate;
        }

        public override double calcMoney(double hours) //Hier wird die Funktion aus der Klasse Engineer
        { //überschrieben, d.h. hier wird jetzt diese Funktion verwendet, anstatt der Basisfunktion
            return billingRate * hours * 1.5d; //Faktor auf 1.5d geändert
        }
    } 

Der Konstruktor ruft hier zuerst den Konstruktor der Basisklasse (Engineer) auf base(name, billingRate) und übergibt die Parameter der CivilEngineer-Klasse.

Nun überschreiben wir die Methode der Basisklasse und ersetzen Sie durch calcMoney der CivilEngineer Klasse.

Jetzt erstellen wir ein Objekt des Engineers und ein Objekt des CivilEngineers.

             CivilEngineer c1 = new CivilEngineer("John",15d);
            Engineer e1 = new Engineer("Keith", 10d); 

Nun erstellen wir eine Liste von Engineers (List<Engineer>) und fügen beide Objekte dieser Liste hinzu:

             List elist = new List();
            elist.Add(c1);
            elist.Add(e1); 

Nun rufen wir bei beiden Objekten die Funktion calcMoney() auf.

             e1.calcMoney(10); //Es wird die Methode Engineer.calcMoney() aufgerufen (Ist ja klar!)
            c1.calcMoney(10); // Es wird die überschriebene Methode CivilEngineer.calcMoney() aufgerufen (Soweit, so gut. Passt alles) 

Jetzt rufen wir die calcMoney()-Methode innerhalb einer foreach-Schleife in der Liste auf:

             foreach (Engineer eng in blalist) //Alle Objekte, egal ob abgeleitet oder nicht, sind vom Typ Engineer
            {
                eng.calcMoney(10);
            } 

Beim ersten Durchlauf wird jetzt die Funktion des Objektes c1 aufgerufen, da dieses zuerst zur Liste hinzugefügt wurde.
Es wird, wie erwartet die überschriebene Methode der abgeleiteten Klasse (CivilEngineer) aufgerufen (also CivilEngineer.calcMoney()), da wir diese in der Klasse Engineer überschrieben (override) haben.

Im darauffolgenden Durchlauf wird jetzt die Funktion des Objektes e1 aufgerufen:
Es wird die Methode der Klasse Engineer aufgerufen, da das Objekt vom Typ Engineer ist – also Engineer.calcMoney(10).

Dies war jetzt mit den Schlüsselwörtern virtual und override.


Jetzt kommen wir zu new:

Fügen wir eine Klasse TankEngineer hinzu, welche die Methode calcMoney() hat, aber hier mit dem new Schlüsselwort deklariert:

    class TankEngineer : Engineer
    {
        public TankEngineer(string name, double billingRate) //Konstruktor der abgeleiteten Klasse
            : base(name, billingRate) //Ruft den Konstruktor der Basisklasse auf, da es von dieser ableitet (benötigt zur Existenz)
        //gleiche Parameter!
        {
            this.name = name; //Zuweisung der Eigenschaften (vererbt)
            this.billingRate = billingRate;
        }

        public new double calcMoney(double hours) //Hier wird die Funktion aus der Klasse Engineer
        { //verdeckt (!) und NICHT überschrieben
            return billingRate * hours * 3.0d; //Faktor auf 3.0d geändert
        }
    }

Nun erstellen ein Objekt vom Typ TankEngineer und fügen es der vorigen Liste mit den zwei anderen Objekten hinzu:

 TankEngineer t1 = new TankEngineer("Robert", 20d); 
 elist.Add(t1); // Füge den TankEngineer hinzu 

Rufen wir nun die Methode calcMoney direkt über das Objekt auf,

  t1.calcMoney(10); // Ruft TankEngineer.calcMoney auf, da vom Typ TankEngineer und Basismethode verdeckt 

Wird die Methode TankEngineer.calcMoney aufgerufen, da diese in der Klasse TankEngineer existiert.

Gehen wir aber nun per foreach wieder durch die Liste (elist):

             foreach (Engineer eng in elist)
            {
                eng.calcMoney(10);
                // 3. Durchgang (t1), ruft die Engineer.calcMoney-Methode auf, da diese existent ist und durch 
                // das new-Schlüsselwort nur verdeckt wurde. 
            } 

so wird hier jetzt die Methode der Basisklasse aufgerufen, da die Liste nur Objekte vom Typ Engineer hält und die Methode nicht überschrieben, sondern nur verdeckt wurde.
D.h. es waren zur Laufzeit beide Methoden des gleichen Namens in beiden Klassen verfügbar.

Zur Veranschaulichung habe ich euch ein kleines Projekt gebastelt, in welchem ihr durch Debugging selbst sehen könnt, wie override bzw. new arbeiten: DOWNLOAD

[C#/.NET] – XML Serialisierung von Objekten

Viele Daten möchte man schnell und unkompliziert abspeichern und wieder in das Programm laden.
Das .NET Framework bietet hierfür unter anderem die Klasse XmlSerializer im Namespace System.Xml.Serialization an.

Der erste Schritt ist natürlich – wie immer – den Namespace einzubinden:

  using System.Xml.Serialization; 

Danach erstellen wir eine Klasse d.h. Bauplan für die zu serialisierenden Objekte:
In meinem Beispiel habe ich jetzt eine Klasse, welche zwei Attribut (Properties) hält.
Mit dem ersten Konstruktor kann ich die Werte direkt zuweisen.
Der zweite Konstruktor wird für die XMLSerialisierung benötigt. Dieser wird vom XMLSerializer aufgerufen.

   
public class User   {    
   
     public string name { get; set; }        
     public int index { get; set; }      

     public User(string name, int index) {          
         this.name = name;      
         this.index = index; 
     }

     public User() { 
 
     }   
} 

Des „schwerste Schritt ist jetzt eigentlich schon geschafft.

Jetzt erstellen wir ein Objekt der Klasse User und füllen die Properties.

 User currentuser = new User("Fabian",1); 

Eine Liste von Objekten (List<User>) zu serialisieren ist natürlich auch möglich und vom Prinzip her identisch.

Nun erstellen zum eigentlichen Thema, der Serialisierung:
Wir erstellen nun ein Objekt der Klasse XmlSerializer:

  XmlSerializer xmlserializer = new XmlSerializer(typeof(User)); 

Hier übergeben wir dem XML-Serialisierer um welche Art von Objekt (typeof()) es sich handelt.
Hier füllen wir in unserem Beispiel typeof(User) ein, bei einer Liste von unserem Objekt typeof(List<User>).

Nun benötigen wir zum Speichern von Dateien auf der Festplatte einen FileStream:

 FileStream str = new FileStream(@"C:\User\xyz\myXMl.xml", FileMode.Create); 

Als Parameter übergeben wir den Speicherpfad und die Option, die dem FileStream sagt, dass er eine Datei erstellen (Create) soll.

Anschließend führen wir die Serialisierung durch:

  xmlserializer.Serialize(str,currentuser); 

Wir übergeben dem XMLSerializier-Objekt hier den den FileStream und unser User-Objekt (currentuser).
Der Serialisierer kümmert sich um den Rest, also Serialisierung und Abspeichern etc.

Zum Schluss einfach den FileStream schließen:

 str.Close(); 

Voilà wir haben unser serialisiertes Objekt auf der Fesplatte. Die Datei sollte in etwa so aussehen:

 <?xml version="1.0" ?> 
- <User>
    <name>Fabian</name> 
    <index> 1 </index>
  </User> 

[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

Durchlaufen von Ordnern und Dateien

Ein kleiner Code, welcher alle Ordner und Dateien durchläuft (rekursiv) und den Pfad in eine Liste schreibt.

 List<string> entitylist = new List<string>(); 
  private void ReadSubDirectories(string path)
        {
            try
            {
                string[] subdirs = Directory.GetDirectories(path);

                foreach (string subdir in subdirs)
                {
                    entitylist.Add(subdir);
                    ReadSubDirectories(subdir);
                }

                string[] subcds = Directory.GetFiles(path);

                foreach (string subcd in subcds)
                {
                    entitylist.Add(subcd);                 
                    ReadSubDirectories(subcd);
                }
            }
            catch { }
        } 

Textausrichtung einer ListView

Normalerweise sollte es kein Problem darstellen, die Ausrichtung eines Textes in einer ListView einzustellen.
Dazu gibt es die Eigenschaft

 TextAlign 

der Klasse

 ColumnHeader 

, welche auch von die ListView zur Darstellung ihrer Spalten nutzt.

Die Ausrichtung lässt sich sehr einfach per Editor oder mit folgendem Code ändern:

 myListView.Columns[myIndex].TextAlign = HorizontalAlignment.Right; 

Zur Auswahl stehen:

  • HorizontalAlignment.Righ
  • HorizontalAlignment.Center
  • HorizontalAlignment.Left

Bisher scheint das auch alles soweit schön zu funktionieren.
Das einzige Probelem ist, dass die Einstellung nicht in der ganz linken Spalte anwendbar ist.
Die ist von Microsoft auch so gewünscht und soll nicht geändert werden.
Man soll es als gegeben hinnehmen.

Ein einfacher Workaround ist nun, eine weitere Spalte davor zu erstellen.
Dieser gibt man einfach die Breite 0.
Nun einfach der Spalte immer Dummywerte zuweisen.

                    
                    myListView.Columns.Add("myDummyColumn");
                    myListView.Columns[myListView.Columns.Count - 1].DisplayIndex = 0;
                    myListView.Columns[myListView.Columns.Count - 1].Width = 0;

Beispielsweise:

  overViewitemDon_lstVw.Items.Add(""); 

Und dann natürlich der zweiten Spalte die Ausrichtung zuweisen:

 myListView.Columns[1].TextAlign = HorizontalAlignment.Right; 

Delegates – Nutzung und Vorteile

In diesem Beitrag geht es um den Nutzen, Sinn und die Funktion von delegates (zu Deutsch Delegaten).
Im Threading Artikel habe ich solch einen schon genutzt um einen anonyme Methode aufzurufen.

Was ist ein Delegate?
Eigentlich nichts weiter als ein Verweis auf eine bestehende Methode.
Codemäßig sieht man auch gleich, dass dieser delegate keinen Methodenrumpf hat und einem Aufruf verblüffend ähnlich sieht, nur dass er – im Gegensatz zu Methodenaufrufen – Parameter benötigt.

 private delegate int myDelegate(int x, int y); 

Nun haben wir einen delegate erzeugt, welcher als Parameter 2 Integer(32)-Werte annimmt und einen int32-Wert (das Ergebnis der Rechnung) zurück gibt.
Nun können wir diesen delegate nutzen um eine Methode aufzurufen.

Erstellen wir hier mal eine Methode

 private void multiplyValues(int x, int y) 

.

 private int multiplyValues(int x, int y) {
 return x * y;
} 

Wichtig ist, dass diese die gleichen Eigenschaften (Parameter, Rückgabewert) hat, wie der delegate!

Nun können wir den delegate als Verweis auf die Methode nutzen:

 myDelegate myMultiplyDelegate = new myDelegate(multiplyValues); 
int result = myMultiplyDelegate(2, 4);  

Multicasting Delegates
Multicasting bezeichnet die Möglichkeit mehrere delegate-Aufrufe in einem zusammen zu fassen.
Dieser Zusammenschluss wird als Multicast-Delegate bezeichnet.
So kann man schnell und einfach mehrere delegates in einer Reihenfolge ausführen.

In meinem Beispiel wollen wir nun eine minder komplexe mathematische Berechnung ausführen.

Erstellen wir dazu erstmal die benötigten Methoden:

 private int divideValues(int x, int y) {
 return x / y;
} 
 private int multiplyValues(int x, int y) {
 return x * y;
} 

Nun haben wir einmal die Funktion zum Teilen und die Funktion zum Multiplizieren.

Diese werden nun mit Hilfe zweier delegates verwiesen:

 myDelegate divDelegate = new myDelegate(divideValues); 
 myDelegate multiplyDelegate = new myDelegate(multiplyValues); 

Nun führen wir die zwei delegates zu einem delegate zusammen:

 myDelegate getPercentage; 
getPercentage = divDelegate;
getPercentage += multiplyDelegate

Führen wir den delegate nun aus:

 int result = getPercentage(98, 100); 

Nun wird zuerst die divideValues Methode aufgerufen (d.h. 98/100). Anschließend wird das Ergebnis mit 100 wird multipliziert.
Das Ergebnis (int result) wird also 98 sein.

Nun ist das ganze nicht so schön, da man für alle delegates nur die Anfangsparameter nutzt.

Die Lösung dafür sind sogenannte references.

delegate void myDelegate(ref int x, ref int y); 

Natürlich müssen die Methoden auch hier referenzierte Parameter erwarten.

Dazu aber mehr in einem anderen Blogpost.

[C#/.NET] – Multithreading in .Net 2.0 #2 parameterisierter Thread

Zu Part 1 geht’s hier lang: KLICK MICH

Nun da wir unseren ersten Thread gestartet haben, wollen wir den Thread nun erweitern, denn wie in Part 1 geschrieben, hat der Thread bisher keine Parameter.

Nehmen wir an wir hätten eine Methode

 public void myCalculation(int i) 

So würden wir den ThreadStart nur so starten können

 ThreadStart myThread = new ThreadStart(myCalculation);  

Nun fehlt uns der Parameter, den die Methode zur Berechnung benötigt.
Diesen können wir nun per delegate und anonymous methods ganz einfach hinzufügen.

Dies geht codemäßig so:

 ThreadStart myThreadStart = delegate { myCalculation(myInt); }; 

Nun können wir den Thread starten

 Thread myThread = new Thread(myThreadStart); 

Das .Net Framework bietet aber auch eine andere Möglichkeit eines parameterisierten Threads, welche intelligenterweise ParameterizedThreadStart genannt wurde:

Dort kann man sehr schnell und ohne delegate einen Thread mit Parametern füttern.

Thread myThread = new Thread (new ParameterizedThreadStart(myCalculation));
myThread.Start (myInt);

Achtung: Die Übergabe des Parameters erfolgt als object. Also muss die Methode ein object als Parameter erwarten.

 public void myCalculation(object i) 

[C#/.NET] – Multithreading in .Net 2.0 #1 Starten eines einfachen Threads

Vorweg:
Hier geht es nur um .NET 2.0, neuere Frameworkversionen haben bessere Funktionen und mehr Möglichkeiten.

Beginnen wir:
Was ist Threading?
Es ist es – ungenau betrachtet – eine parallele Abarbeitung von Aufträgen, also einfach ausgedrückt, es wird versucht mehr als eine Sache gleichzeitig zu machen.
Also was ist dann ein Thread?
Sagen wir einfach mal es sei ein Platz an dem Code ausgeführt wird.

Einführung:

Das .Net Framework wurde schon von Grund auf dafür designed, multithreading fähig zu sein.
Ich zitiere hier mal einfach aus dem MSDN:

Der System.Threading-Namespace stellt Klassen und Schnittstellen bereit, die die Programmierung mit mehreren Threads unterstützen und Aufgaben wie das Erstellen und Starten neuer Threads, die Synchronisierung mehrerer Threads sowie das Anhalten und das Abbrechen von Threads vereinfachen.

Laut diesem Abschnitt soll es ganz einfach sein Threads zu starten und zu beenden.
Das ist es auch. Die Schwierigkeit kommt es mit der Abstimmung untereinander, also dem Ressourcenmanagement zwischen Threads.

Wie starte ich einen Thread?

Wie man aus dem MSDN-Artikel entnehmen konnte, wird also der Namespace „System.Threading“ benötigt, welchen wir über

 using System.Threading 

einbinden können.

Nun zum eigentlichen Grundcode eines Threads.
Zuerst müssen wir einen ThreadStart anlegen und definieren, welche Methode er ausführen soll.

ThreadStart startThread = new ThreadStart(myClassObject.myMethod); 

Zwischeninfo: Es wird jetzt auffallen, dass wir der Methode keine Parameter übergeben konnten. Das ist so auch richtig, dazu aber später mehr.

Daraufhin muss man den Thread mit dem ThreadStart als Parameter anlegen:

Thread myThread = new Thread(startThread);

Nun starten wir den Thread ganz einfach mit

myThread.Start(); 

Fortsetzung folgt…