Zum Inhalt springen

Whiz-zarD

Mitglieder
  • Gesamte Inhalte

    2083
  • Benutzer seit

  • Letzter Besuch

  • Tagessiege

    51

Reputationsaktivitäten

  1. Like
    Whiz-zarD hat eine Reaktion von chris.k erhalten in netzteil Rasspberry pi   
    Ich hab ein Netzteil mit 1,5A Ausgangsseitig. Besser wäre aber 2A oder mehr. Ich hab das Problem, wenn ich mal eine Festplatte ranhänge, dann startet der Raspberry neu, weil das Netzteil beim Anfahren der Festplatte in die Knie geht. Kann aber auch vielleicht daran liegen, dass das Netzteil schlecht verarbeitet ist und die verbauten Kondensatoren nichts taugen.
  2. Like
    Whiz-zarD hat eine Reaktion von Rabber erhalten in Fachkräftemangel - Gründe und Auswege   
    Das sind 5% von der Summe des Kredites. Also 5% von 77.000 € macht 3.850 €.
    Also kann ich jährlich einmal 3.850 € an die ING-Diba bezahlen. (weitere Sondertilgungen sind mit Gebühren verbunden)
    Ich habe noch mal nachgeschaut. Ich bezahle an die ING-Diba 272,21 € und an die KfW 188,77 €. Macht zusammen 460,98 €.
    Dann noch das 191,00 € Wohngeld an die Verwaltung. Dann liege ich bei 651,98 €. Mit Strom, Internet, Telefon, etc. liege ich bei 850 €. Wie du auf die 900 € allein nur für den Kredit kommst ist mir ein Rätsel.
  3. Like
    Whiz-zarD hat eine Reaktion von Jony erhalten in Ausbildungs FIAE Themen   
    UML ist aus meiner Sicht einfach nicht wirklich wichtig. DIe Praxis zeigt deutlich, dass UML versagt hat. Kaum keiner verwendet diese Diagramme und selbst die IHK kennt wohl die Unterschiede einzelner Diagramme nicht. Daher wäre es wohl besser, nur das absolut nötigste zu lehren, damit sie die Prüfung bestehen, damit mehr Zeit für andere Dinge bleiben.
    Viel wichtiger finde ich das tiefgründige Wissen. Angefangen mit einfachen Datentypen und warum z.B. Fließkommazahlen für Geldbeträge ungeeignet sind. Dann Zeiger bzw. Referenzen (Call by Value, Call by Reference) und dann Datenstrukturen, z.B. Stapelspeicher, Mengen, Listen, Bäume, etc.
  4. Like
    Whiz-zarD hat eine Reaktion von JimTheLion erhalten in Fachkräftemangel - Gründe und Auswege   
    Wenn ich Akirai verstanden habe, ging es ihm gar nicht darum, dass man sich privat weiterbildet, sondern dass man auch Interesse an neuen Ideen zeigen sollte. Das kann auch während der Arbeitszeit passieren. Ich lese auch während der Arbeitszeit Fachzeitschriften oder schaue mir Videos auf Pluralsight an. Privat habe ich dafür kaum Zeit.
    Ich kenne selber einige Entwickler, die vor ca. 25 Jahren Informatik studiert haben und meinen, das was sie damals gelernt haben, immer noch State-of-the-Art ist und neue Ideen als Teufelszeug und Hipster-Kram betiteln und hier geht es gar nicht mal um die neue Ruby on Rails-Sau, die durchs Dorf getrieben wird, sondern um Dinge wie z.B. Clean Code. Auch in der Firma, wo ich arbeite, meinen einige, Clean Code ginge hier bei uns gar nicht, weil die Logik der Anwendung so kompliziert sei und stellen sogar das Wissen von Personen wie Martin Fowler oder Robert C. Martin in Frage. Vor einiger Zeit hatte ich eine Auseinandersetzung mit einem Arbeitskollegen, weil er das yield return-Schlüsselwort in C# für Schlimm hält, weil der Kompiler sehr viel IL-Code drumherum baut. Was interessiert es mich, was der Kompiler da rum baut, wenn dadurch die Lesbarkeit des eigentlichen Codes besser wird und die Performance sich nicht maßgeblich verschlechtert? Stattdessen werden weiterhin fleißig gigantische Listen produziert, bei denen ständig der Arbeitsspeicher wegplatzt. Mit solchen Leuten kannst du einfach nicht reden, weil sie alles blockieren und sich auch nicht weiterbilden wollen.
  5. Like
    Whiz-zarD hat eine Reaktion von Rienne erhalten in Fachkräftemangel - Gründe und Auswege   
    Und ich garantiere dir, dass kaum einer OOP wirklich verstanden hat.
     
     
  6. Like
    Whiz-zarD hat eine Reaktion von Britanny erhalten in Modellieren eines Objektdiagramm für das Projektmanagement   
    Ich glaube, du gehst einen falschen Weg.
    Vielmehr sollte man sich die Frage stellen, was du überhaupt erreichen willst? So viel, wie ich es verstanden habe, willst du ein Projekt modellieren und es mit Leben füllen. Die Idee in Phase 1 ist also schon der Startschuss für ein Projekt. "Phase 1" ist damit ein Status vom Projekt und dieses Projekt reichst du nun von Station zu Station weiter und jedes Mal ändert sich der Status. Validierungen überprüfen, ob der jeweilige Status geändert werden kann. Ein Projekt ablehnen ist dann auch nur ein Status.
    Daraus resultieren eigentlich schon deine Tabellen:
    Ein Projekt besteht dann aus einem Status, einer Idee (Text?), Projektcharakter (Enum?), Projektumfeld (?), Business Case (Text?), Businessplan, ... Und das brichst du dann weiter auf. Je nach dem, wie du die einzelnen Punkte aufbauen möchtest, resultieren weitere Tabellen daraus, wie z.B. ein Businessplan, der aus mehreren Schritten besteht oder dein Projektumfeld, was aus meineren Eigenschaften besteht.
    Ein Klassendiagramm für ein Ablauf zu missbrauchen halte ich für falsch.
     
  7. Like
    Whiz-zarD hat eine Reaktion von Rabber erhalten in Fachkräftemangel - Gründe und Auswege   
    Das predige ich schon seit 15 Jahren.
    Ich habe früher selber als Mechatroniker gearbeitet und schon damals jammerten die Firmen, dass sie keine Fachkräfte finden und somit mit der Produktion in den Rückstand geraten. Es wurden aber keine Handwerker gesucht, sondern Ingenieure aber die stellen sich nicht freiwillig in die Halle und schrauben etwas zusammen. Von daher kann der Produktionsrückstand wohl kaum mit fehlenden Ingenieuren zusammenhängen. Vielfach haben die Betriebe ein Überangebot an Ingenieuren, sodass sie nur noch in der Firma sitzen und Kekse fressen (ich habe schon sowas erlebt). Wenn Handwerker gesucht werden, dann schön bei Zeitarbeitsfirmen, denn dann kann man den Handwerker wieder schnell rausschmeißen und mittels Kanban kann man die Arbeitsschritte auch so klein halten, sodass jeder Depp die Schritte ausführen kann und dann kann man schön den Preis bei den Zeitarbeitsfirmen drücken, weil die Handwerker ja keine spezielle Ausbildung mehr brauchen, denn drei Schrauben reindrehen lernt man binnen wenigen Minuten.
  8. Like
    Whiz-zarD hat eine Reaktion von MarcoDrost erhalten in Wie spricht man Bewerber/innen an?   
    Mich persönlich würde das sogar sehr abschrecken. Ich habe schon in solchen Betrieben gearbeitet und überall gabs da einen gewissen Gruppenzwang und man wurde schief angeschaut, wenn man nicht zum Feierabend noch mit den Arbeitskollegen ein Bier trinken möchte, sondern einfach nur noch nach Hause möchte. Ich habe auch eher die Erfahrung gemacht, wenn eine Firma so eine Kultur lebt, dann wird damit irgendwas kompensiert, wie z.B. eine unterdurchschnittliche Bezahlung. Gerade in der Spielebranche und in Startups ist mir das extrem aufgefallen. Man versucht auf Hip und Cool zu machen und zeigt auch angebliches Interesse seinen Mitarbeitern gegenüber aber im Grunde will man nur, dass die Mitarbeiter ihren Arbeitsplatz nicht verlassen, damit sie auch noch nach dem Feierabend freiwillig arbeiten und am Besten noch für wenig Geld.
    Derzeit lese ich auch in Stellenangeboten häufig, dass eine Firma eine "flache Hierarchie" besitzt. Auch da wäre ich sehr vorsichtig, denn es kann auch bedeuten, dass keiner Verantwortung übernehmen möchte und die Verantwortung immer zum nächsten weiterreicht. Sowas habe ich gerade in meiner aktuellen Firma. 
    Solche Benefits hören sich zwar immer ganz gut an aber man sollte dies auch hinterfragen und nicht alles gedankenlos hinnehmen, denn oftmals steckt da auch ein gewisses Kalkül dahinter und nicht nur die reine Nächstenliebe.
  9. Like
    Whiz-zarD hat eine Reaktion von neinal erhalten in Ausbildung ohne Programmierung   
    Gerade in der Bankenbranche werden immer mehr Entwickler gesucht, weil viele Banken derzeit vor großen Problemen stehen, da sie ihre wildwüchsigen Excel- und Access-Insellösungen gegen standardisierte und dokumentierte Software austauschen müssen. Solche Software lässt sich nicht durch ein Haufen Inder oder Chinesen realisieren, da Regularien eingehalten und erfüllt werden müssen, wie z.B. eine Lückenlose und flexible Historisierung der Daten und das stellt den Entwicklern vor große Herausforderungen. Da tauchen dann plötzlich solche Begriffe auf, wie z.B. Data Vault.
  10. Like
    Whiz-zarD hat eine Reaktion von MarcoDrost erhalten in Wie spricht man Bewerber/innen an?   
    Sehe ich genauso. Deswegen schaue ich mir solche Stellenangebote auch nicht mehr weiter an. Allein wenn ich nur die Stellenanzeige anschaue:
    Da muss ich nur mit dem Kopf schütteln, dann das ist eine allgemeine Beschreibung, was ein Entwickler überhaupt macht. Da steckt überhaupt keine Information, was eigentlich gewünscht wird. Genauso gut könnte man diesen Satz auch weglassen. Nicht einmal der Technologie-Stack wird hier klar. Handelt es sich hier nun um eine Desktop Applikation und man arbeitet vielleicht mit Swing oder ist es eine Smartphone-App und arbeitet mit Android oder ist es sogar eine Web-App und arbeitet mit React/Angular/Was-auch-immer? Sucht man überhaupt einen Frontend-Entwickler oder eher jemanden im Backend-Bereich oder sucht man einen Allrounder? Auf was lässt man sich da also ein?
    Weiterhin steht dort u.a.
    Ja, welche denn? MSSQL, OracleDB, MySQL, MariaDB, ... ? Oder geht es hier um DB2, weil Erfahrung im IBM-Umfeld vom Vorteil wäre? Bin ich, der hauptsächlich im OracleDB-Umfeld arbeitet, der richtige? Und nein, relationale Datenbank ist nicht gleich relationale Datenbank.
    Es gibt da einen schönen Spruch: "Der Knochen kommt nicht zum Hund" oder "Seit wann kommt der Knochen zum Hund?" Wieso sollte ich mich also auf so eine Stelle bewerben? Eine Firma sucht Mitarbeiter. Also sollte doch die Firma erstmal in Vorleistung gehen und sich präsentieren.
  11. Like
    Whiz-zarD hat eine Reaktion von ddd2 erhalten in Wie spricht man Bewerber/innen an?   
    Sehe ich genauso. Deswegen schaue ich mir solche Stellenangebote auch nicht mehr weiter an. Allein wenn ich nur die Stellenanzeige anschaue:
    Da muss ich nur mit dem Kopf schütteln, dann das ist eine allgemeine Beschreibung, was ein Entwickler überhaupt macht. Da steckt überhaupt keine Information, was eigentlich gewünscht wird. Genauso gut könnte man diesen Satz auch weglassen. Nicht einmal der Technologie-Stack wird hier klar. Handelt es sich hier nun um eine Desktop Applikation und man arbeitet vielleicht mit Swing oder ist es eine Smartphone-App und arbeitet mit Android oder ist es sogar eine Web-App und arbeitet mit React/Angular/Was-auch-immer? Sucht man überhaupt einen Frontend-Entwickler oder eher jemanden im Backend-Bereich oder sucht man einen Allrounder? Auf was lässt man sich da also ein?
    Weiterhin steht dort u.a.
    Ja, welche denn? MSSQL, OracleDB, MySQL, MariaDB, ... ? Oder geht es hier um DB2, weil Erfahrung im IBM-Umfeld vom Vorteil wäre? Bin ich, der hauptsächlich im OracleDB-Umfeld arbeitet, der richtige? Und nein, relationale Datenbank ist nicht gleich relationale Datenbank.
    Es gibt da einen schönen Spruch: "Der Knochen kommt nicht zum Hund" oder "Seit wann kommt der Knochen zum Hund?" Wieso sollte ich mich also auf so eine Stelle bewerben? Eine Firma sucht Mitarbeiter. Also sollte doch die Firma erstmal in Vorleistung gehen und sich präsentieren.
  12. Like
    Whiz-zarD hat eine Reaktion von Britanny erhalten in Festfahren in Details beim programmieren   
    Wenn man zu sehr in den Details feststeckt, dann sollte man sich überlegen, ob die Lösung überhaupt die richtige ist?
    Zu viele Details bedeutet oftmals auch zu viel Code, der auch instabil ist. Man will wohl zu viel auf einmal erledigen. Daher wäre es wohl ratsam, hier ein Schlussstrich runterzusetzen und noch mal die Aufgabe überdenken. Evtl. müssen die Teilschritte noch mal unterteilt werden. Ratsam wäre auch mit einem Kollegen über die Aufgabe zu sprechen. Oftmals kommen da Ideen, an die man nicht gedacht hat. Pair-Programming kann in solchen Situationen auch hilfreich sein.
     
  13. Like
    Whiz-zarD reagierte auf Rienne in Projektangtrag: Entwicklung von Automatisierten CSV Datenübertragung und CSV Datenbankabgleichung   
    Ich finde es immer wieder interessant, was die IHKs so alles im Vorfeld schon im Antrag wissen wollen, was definitiv eigentlich zur Projektdurchführung zählen sollte.
    Klar kann man, wenn man es vorher schon weiß, angeben womit man programmiert. Aber eigentlich gehören solche Entscheidungen in die Definitionsphase und so etwas wird ja erst mit dem Pflichtenheft festgelegt.
    Genauso diese genauen Zeitangaben - man weiß, man hat 70h und grob sollte man so etwas auch vorher wissen, z.B. als Dauer der einzelnen Phasen; aber doch nicht die genaue Dauer jedes einzelnen Arbeitspaketes - denn auch die sollten erst NACH Projektstart definiert werden...
    Du hast doch noch gar nicht mit dem Projekt begonnen, oder?
    Bin immernoch skeptisch, bei einer festen Zeitvorgabe und ALLEINIGER Projektdurchführung, zu behaupten man würde ein Projekt agil durchführen.
    Ich kann jedoch verstehen, wenn die IHK den Antrag aufgrund des fehlenden Detailgrades der Beschreibung ablehnt.
    DU solltest dir immer die Frage stellen: Versteht jemand, der weder die Firma noch mein Tätigkeitsgebiet kennt, was ich da genau mache?
    Dazu ist es oft hilfreich z.B. etwas genauer zu erläutern um was für Prozesse es sich handelt, was der Kunde macht und was er genau geändert haben möchte.
    Du schreibst quasi lediglich: Eine CSV soll eingelesen und geprüft werden. Nichts zur Architektur, dem detaillierten Prozess, etc pp
  14. Like
    Whiz-zarD hat eine Reaktion von JimTheLion erhalten in Asyl-berechtiger , Flüchtlinge   
    Darf ein Mensch jetzt kein Hobby mehr haben und dies im Internet zeigen, weil ein potenzieller, zukünftiger Arbeitgeber nach dieser Person auf Facebook suchen könnte und herausfindet, dass die Person Hobbies hat, die er nicht versteht? ... Sorry aber Privat ist Privat und Arbeit ist Arbeit. Wenn ein Arbeitgeber meint, er hat Vorurteile gegenüber anderen Menschen, weil ihm ein Profilbild nicht passt, weil er es nicht kapiert und auch keine Lust hat hat, zu recherchieren, dann ist er wohl auch nicht der richtige Arbeitgeber und von solchen Firmen sollte man dann auch einen großen Bogen machen.
    Sorry, aber jeder der mal was von American Football und NFL gehört hat, kann was mit dem Begriff "Raiders" anfangen. Gemeint ist die Mannschaft Oakland Raiders. Ein Blick unter Google verrät auch, dass "Raiders Nation" die Fans dieser Mannschaft betitelt. Dazu gibt es sogar einen Wikipedia-Eintrag. Also bitte einmal das Gehirn einschalten ...
  15. Like
    Whiz-zarD hat eine Reaktion von JimTheLion erhalten in Im Beruf ankommen   
    Das Wort "Codeäffchen" lese ich öfters und frage mich jedes Mal, was das bittesehr sein soll?
    Offenbar entstammt das Wort vom Infinite-Monkey-Theorem. Dabei frage ich mich immer, was das nun mit Softwareentwicklung zu tun hat? Vielleicht gibt es Buden, die solange auf der Tastatur rumhacken, bis irgendwann mal eine Software dabei rauskommt aber wenn eine Firma ernsthaft Geld mit ihrer Software verdienen möchte, dann ist es schnell vorbei mit dem "Codeäffchen". Softwareentwicklung ist nun mal mehr, als nur Code zu schreiben. Heutzutage haben wir es mit einem gigantischen Technologiestack zu tun, der irgendwie orchestriert werden muss. Mit ein paar "Codeäffchen" kommt man da nicht weit und wenn eine Firma auch auf wartbaren Code achten möchte, dann müssen auch Entwickler ran, wie was von Clean Code verstehen. Darüber hinaus ist auch sehr viel Kommunikation von Nöten. Also die sog. "Soft Skills" sind heutzutage auch sehr wichtig geworden. 
    Glaube mir mal, so weit weg von "state of the art" ist das nicht.
    Mag sein, dass Startup-Hipster andere Technologien verwenden, aber ist würde davon mal ausgehen, dass viele Firmen sowas wie Hibernate, Spring MVC oder Bootstrap gar nicht kennen. Man darf sich auch nicht von den Stellenangeboten verunsichern lassen. Oftmals spielen sie da Bullshit-Bingo und feuern alles ab, was denen so einfällt. Die Realität sieht dann meist anders aus. Bewirb dich einfach auf Junior-Entwickler-Stellen. Du wirst sehen, dass andere auch nur mit Wasser kochen und auch nicht wirklich viel schlauer sind, als du selbst. Die Erfahrung kommt erst mit den Jahren. Also mache dir da mal keine Sorgen.
  16. Like
    Whiz-zarD hat eine Reaktion von Striewe erhalten in Fragen mündliche Prüfung   
    Dazu fällt mir noch ein:
    Welche Alternative gibt es zu POP3 und ist die Alternative nicht sinnvoller?
  17. Like
    Whiz-zarD hat eine Reaktion von Britanny erhalten in Tabellen in Html bzw. css   
    Du erstellt mit HTML ein Tabelle und mit CSS passt du die mit deinem Designstil an. CSS ist eine Stylesheet-Sprache, mit der man das Erscheinungsbild von Elementen anpasst. Mehr ist CSS nicht. Kannst ja z.B. hier mal reinschauen, wie sie die Tabellen gestaltet haben
  18. Like
    Whiz-zarD hat eine Reaktion von Britanny erhalten in Projektantrag: Entwickeln einer Web-Anwendung „Zeitmanagement“ mit einer Datenbankanbindung   
    Mag sein, dass die Prüfer da nicht ganz so streng draufschauen, aber ich finde den Antrag sehr fragwürdig. Auf der einen Seite wird die Software als riesiges, komplexes Konstrukt dargestellt aber auf der anderen Seite wird gar nicht auf die komplexität eingegangen.
    Als erstes die Projektbeschreibung:
    Sie wird dargestellt als würde die Software komplexe Strukturen der Projekt-Phasen in unterschiedlichen Firmen abbilden, kontrollieren und steuern können. Die Aufgabe des Azubis ist die Implementierung der Basisfunktionalität. Gut, lassen wir es einmal so wirken.
    Bis jetzt liest sich wie ein PR-Text eines Vertrieblers, der den Wunschzustand erwähnt aber wünschen kann man sich ja vieles.  Zur Nutzen/Kostenberechnung sage ich mal nichts. Das würde jetzt den Rahmen sprengen. 
    Punkt 2:
    Hier wird es mal etwas konkreter, was die Software können soll:
    Projekte anlegen Projekte verwalten (auf welche Weise auch immer?) Projekte tabellarisch oder als Ganttdiagramm darstellen Das wars? Wo ist die erwähnte Steuerung und Kontrollierung der Projekte?
    Und das soll dann verkauft werden? Okay, vielleicht ist das auch nur die Basisfunktionalität. Wer weiß? 
    Punkt 3.1:
    Du erwähnst, dass das Projekt mittels dem Entwicklungsmodel des Wasserfallmodell und der agilen Entwicklung entwickelt werden soll. Beides schließt sich aber gegenseitig aus. Das Wasserfallmodel beruht auf sehr starren Phasen, während die agile Entwicklung bestmöglich gar nicht aus Phasen besteht. Agile Entwicklung beruht auf vier Grundsätze:
    Menschen und Interaktionen stehen über Prozessen und Werkzeugen Funktionierende Software steht über einer umfassenden Dokumentation Zusammenarbeit mit dem Kunden steht über der Vertragsverhandlung Reagieren auf Veränderung steht über dem Befolgen eines Plans Das Wasserfallmodell verstößt schon gegen drei der vier Grundsätze. Ich nehme mal an, du meinst eher das V-Modell.
    Punkt 3.2:
    Wieso wird so oft MySQL erwähnt? Mag ja sein, dass ihr MySQL verwendet aber ihr wollt die Software verkaufen, also muss sie auch mit anderen Datenbanken zurecht kommen. Angenommen, ein Kunde hat MSSQL oder OracleDB im Einsatz. Was dann?
    Punkt 3.3:
    In der Implementierungsphase wird mit vier Sätzen ein generisches Login-System beschrieben. Das Gantt-Diagramm muss mit einem Satz auskommen. Wie wird das Diagramm überhaupt generiert? Ist das eine HTML-Tabelle? Eine Grafik? Schreibst du die Bibliothek dafür selber? Wird da was fertiges verwendet? Die eigentliche Aufgabe der Software wird hier gar nicht beschrieben. Ist das generieren des Gantt-Diagramms überhaupt deine Aufgabe oder implementierst du nur das Login-System?
    Punkt 4:
    In der "Entwurf"-Phase designst du 9 Stunden lang Datenbank-Tabellen. Wozu? In der Phase "Implementierung" lässt du diese Tabellen mit dem Entity Framework generieren. Auch designst du in der "Entwurf"-Phase noch Views. Wozu? Weshalb? Welchen Grund haben die Views? Willst du die komplette Business-Logik als Views abbilden? Das halte ich für fatal. Ihr habt doch das mächtige Entity Framework und bitte sag mir jetzt nicht, dass ihr das Framework nicht richtig einsetzt und nur stumpf SQL-Queries mit der ExecuteQuery()-Methode ausführt. 
    Fazit:
    In der gesamten Projektbeschreibung wird aus meiner Sicht überhaupt nicht klar, was du machen möchtest. Es wird eine angeblich riesige Software vorgestellt, die aber in Wirklichkeit nur sehr klein ist und auf deine Aufgabe gehst du nicht mal ein. Der Hauptaugenmerk liegt irgendwie beim Login-System aber das kann doch nicht deine einzige Aufgabe sein. 
    Ansonsten das noch, was @stefan.macke schrieb.
  19. Like
    Whiz-zarD hat eine Reaktion von thereisnospace erhalten in C# OOP - Eure Meinung   
    Dein Problem mit dem '\r' ist folgendes:
    Du hast ein String, der aus mehreren Zeilen besteht. Das Zeilenende unter Windows wird standardgemäß mit "\r\n" dargestellt. Das sind nicht-druckbare Steuerzeichen. Das \r steht für "cariage return" und das \n für "new line". Reguläre Ausdrücke werden aber standardgemäß pro Zeile ausgewertet und das eine Zeile wirklich beendet ist, leitet nur das \n ein. Somit bleibt \r stehen.
    Wenn du es unbedingt mit einen regulären Ausdruck ermitteln möchtest, dann musst du es so schreiben:
    Regex rsource = new Regex("(?<=Source\\=)[^\r]+"); Aber reguläre Ausdrücke würde ich persönlich vermeiden. Die versteht doch kein Schwein. Ich würde durch jede Zeile der Ini-Datei iterieren und jede Zeile per Split() mit dem '='-Zeichen teilen. So habe ich den Schlüssel und den Wert getrennt und kann damit arbeiten. 
    Versuche aber mal die Settings und das Laden der Settings zu trennen. Also dass du eine Klasse Settings hast:
    public class Settings { public string source { get; set; } public string Destination { get; set; } } Und eine Klasse z.B. mit dem Namen SettingsLoader, die eine Methode bereitstellt, die die Settings aus der Ini-Datei lädt und dir eine Instanz vom Typ Settings zurückliefert. Also z.B:
    public class SettingsLoader { public Settings Load(string fileName) { ... } } So trennst du die Datenstruktur von der Logik. Angenommen, du hast neben der Ini-Datei als Quelle für die Einstellungen jetzt noch eine Datenbank. Dann müsstest du ja die Settings-Klasse um weitere Methoden aufblähen, die die Daten aus der Datenbank lesen und dann kommt vielleicht die dritte (z.B. aus Textboxen einer WinForms-Anwendung), vierte und fünfte Quelle. Dann wird die Klasse sehr riesig und unübersichtlich. Das möchte man aber nicht. Man sollte das Ziel verfolgen, eine Klasse so klein wie möglich zu halten. Einige sagen, eine Klasse darf nicht mehr als 200 Zeilen besitzen aber ich finde so dogmatisch sollte man es nicht halten, aber man sollte sich daran orientieren. Um also mehrere Quellen abzugrasen sollte man pro Quelle eine Klasse schreiben, die die Einstellungen einliest und zurückgibt.
  20. Like
    Whiz-zarD hat eine Reaktion von StefanE erhalten in C# OOP Probleme   
    Wieso sollte man dich töten wollen?
    Softwareentwicklung ist nun mal ein Reifeprozess. Niemand liest nur ein Buch und kann gleich wunderbar sauberen Code schreiben. Mein Code sah zum Anfang auch mies aus und selbst Robert C. Martin, der das Buch "Clean Code" geschrieben hat, sagt von sich aus, dass er nicht die Weisheit mit Löffeln gefressen hat und es auch bei seinen Code-Beispielen sicherlich noch Verbesserungspotenzial gibt aber nur durch Ausprobieren lernt man. 
    Du hast schon richtig erkannt, dass man fürs Einlesen der Datei eine eigene Klasse benötigt. Allerdings gehört die Logik nicht in den Konstruktor. Der Konstruktor dient zur Initialisierung der Klasse. Der Name der Klasse sollte auch die Aufgabe widerspiegeln, was die Klasse tut. "DateiEinlesen" ist vielleicht gut, aber geht es vielleicht noch konkreter? Ich weiß, dass es eine CSV-Datei ist. Vielleicht eher CsvReader?  Wobei dieser Name auch wieder sehr allgemein ist. In der CSV-Datei steckt ja eine Tabelle. Welche Daten besitzt die Tabelle? Vielleicht kann man der Tabelle einen Namen geben. Eine CSV-Datei ist ja eine Art der Serialisierung. Das Verfahrung um so eine Tabelle in ein Objekt zu überführen, nennt man auch Deserialiserung. Das kann man ja erst mal im Hinterkopf behalten.
    Zuerst würde ich mir aber erst mal eine geeignete Datenstruktur überlegen. In der CSV-Datei stecken ja Daten. Ich nehme jetzt mal als Beispiel, dass die CSV-Datei Daten zu Personen beinhaltet:
    Name;Vorname;Geschlecht;Alter Doe;John;Maennlich;38 Also würde ich erst mal eine Klasse für diese Daten erstellen:
    public class Person {     public string Name { get; set; }     public string Vorname { get; set; }     public Geschlecht Geschlecht { get; set; }     public int Alter { get; set; } } public enum Geschlecht {     Maennlich     , Weiblich } Nun könnte ich mich darum kümmern, eine(!) Datei einzulesen. Ich habe eine Datenstruktur und ich weiß, dass ich eine CSV-Datei deserialisieren muss. Also könnte man die Klasse z.B. PersonCsvDeserializer nennen. In dieser Klasse soll es eine Methode geben, die Deserialize() heißt. Ich verzichte hier jetzt erst mal bewusst auf ein Interface, weil ich denke, dass es für dich bis hier hin schon kompliziert genug ist. Das Interface werde ich später noch mal erklären. Erst mal kümmern wir uns darum, was wir alles brauchen, um eine Datei zu deserialisieren. 
    Was muss die Klasse PersonCsvDeserializer alles wissen, um eine CSV-Datei deserialisieren zu können? Man könnte vielleicht im ersten Schritt auf die Idee kommen, dass die Klasse den Pfad und Dateinamen benötigt. Mit den Informationen aus dem letzten Absatz könnte ein erster Entwurf so aussehen: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {       // ...     } } Als Rückgabewert habe ich IEnumerable<Person> gewählt, weil IEnumerable<T> ein sehr allgemeines Interface ist und einen Enumerator (auf deutsch: Aufzählung; in anderen Sprachen auch Iterator genannt) zur Verfügung stellt, mit dem wir über die Daten iterieren können (mit der foreach-Schleife). Sowohl IList<T>, ICollection<T>, IDictionary<T>, Array und weitere Klassen implementieren dieses Interface und mehr als über die Daten iterieren wollen wir nicht. Wenn wir später damit mehr machen wollen, können wir es leicht mit Linq in eine Collection, List, Array oder auch in ein Dictionary umwandeln. Die Deserialize()-Methode soll also eine Aufzählung von Personen zurückliefern.
    Normalerweise macht man es anders, aber aus einfachheit behaupte ich mal frech, dass die erste Zeile in der CSV-Datei immer ein Header besitzt. In der Implementierung überspringe ich den Header per Linq mit der Skip()-Methode. Die Deserialize()-Methode soll also folgendes machen:
    Die Datei lesen Durch die Datenzeilen iterieren Pro Datenzeile ein Person-Objekt erstellen Die Person-Objekte als Aufzählung zurückliefern Der erste Entwurf könnte daher folgendermaßen aussehen:
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string line in File.ReadAllLines(fileName).Skip(1))         {             string[] elements = line.Split(';');             result.Add(new Person             {                 Name = elements[0],                 Vorname = elements[1],                 Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),                 Alter = Convert.ToInt32(elements[3])             });         }         return result;     } } Die Methode macht zwar was sie soll, aber ist sie wirklich übersichtlich? Nicht wirklich. Wir haben hier mehrere Ebenen miteinander vermischt. Wir können also mit dem Refactoring anfangen. z.B. das
    File.ReadAllLines(fileName).Skip(1) Wofür ist das genau gut? Wenn man den gesamten Kontext kennt, weiß man es zwar aber eigentlich liegt der Code-Abschnitt eine Ebene Tiefer. Es hantiert mit Dateien und hat mit der eigentlichen Aufgabe der Deserialiserung wenig zu tun. Also sollte man diesen Teil in eine separate Methode packen:
    private IEnumerable<string> ReadDataFromFile(string fileName) {     return File.ReadAllLines(fileName).Skip(1); } Somit wandert das Skip(1) in eine tiefere Ebene und interessiert uns in der Deserialize()-Methode nicht mehr. Als nächstes fällt aber auf, dass wir ein String mit Split() in ein Array teilen und aus diesem Array dann die einzelnen Personendaten herausfischen. Diesen Vorgang nennt man auch Parsing. Also könnten wir diesen Teil auch in eine Methode auslagern:
    private Person Parse(string serializedData) {     string[] elements = serializedData.Split(';');     return new Person     {         Name = elements[0],         Vorname = elements[1],         Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),         Alter = Convert.ToInt32(elements[3])     }; } Unsere Klasse sieht dann bis jetzt folgendermaßen aus: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string serializedData in ReadDataFromFile(fileName))         {             Person person = this.Parse(serializedData);             result.Add(person);         }         return result;     }     private IEnumerable<string> ReadDataFromFile(string fileName)     {         return File.ReadAllLines(fileName).Skip(1);     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Nun ist Deserialize() doch recht gut lesbar. Wir lesen die Daten aus der Datei, parsen die Daten und erhalten ein Person-Objekt, welches wir dann in eine Liste packen und zum Schluss geben wir die Liste zurück.
    Es gäbe hier noch weiteres Verbesserungspotenzial aber ich belasse es erst mal hierbei. Ein paar Hinweise gebe ich aber noch:
    Fehler-Handling? Was passiert, wenn z.B. die Datei nicht existiert? Ist das erzeugte Objekt List<Person> wirklich eine gute Wahl? Angenommen, wir haben es mit einer riesigen CSV-Datei (mehrere Gigabytes) zu tun, die größer ist, als unser Arbeitsspeicher. Hier schmeiße ich mal das "yield return"-Schlüsselwort in den Raum. Auch ist das indexierte Zugreifen auf das Array in der Methode Parse() nicht wirklich glücklich gelöst. Was passiert nämlich, wenn mal eine Spalte in der Datei hinzukommt? Dann muss man ja auch den Code anpassen. Das will man aber eigentlich gar nicht. Zu diskutieren wäre auch, ob die Variable fileName nicht doch besser eine Instanzvariable sein sollte, die per Konstruktor reingereicht wird. Es fällt ja auf, dass die Methoden Deserialize() und ReadDataFromFile() den Dateinamen benötigen. Also stellt fileName ja eine gewisse Abhängigkeit dar, die die Klasse benötigt, um arbeiten zu können.  Als Überlegung kannst du ja selber mal schauen, wie man mit solchen Situation umgehst.
    Um später im Hauptpgramm alle Personen zu iterieren könntest du nun folgendes schreiben:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");     PersonCsvDeserializer deserializer = new PersonCsvDeserializer();     foreach(string fileName in fileNames)     {         IEnumerable<Person> persons = deserializer.Deserialize(fileName);         foreach (Person person in persons)         {             // ...         }     } } Nach dem selben Prinzip, wie bei der PersonCsvDeserializer-Klasse kannst du ja mal überlegen, wie man nun diesen Code refactoren an.
    Ab hier wird es noch etwas technischer und tiefgreifender. Ich möchte dir noch zwei Techniken zeigen, die du aber erst mal nicht umsetzen brauchst.
    "Inversion of Control" und "Dependeny Injection"
    In der Klasse PersonCsvDeserializer fällt auf, dass die Klasse von einer Datei abhängig ist aber die Daten können vielleicht aus einer Datenbank kommen oder wir schreiben die CSV-Daten direkt in eine grafische Oberfläche. Möchte man jetzt für jeden Anwendungsfall eine eigene Klasse schreiben? Eigentlich nicht. Die Abhängigkeit zur Datei muss also aufgelöst werden. Das .Net-Framework bietet ja die abstrakte Klasse TextReader, die so ziemlich alles darstellen kann. Ein Reader, der eine Datei liest oder aus einem TCP-Stream oder aus einer Datenbank, etc. Anstatt also den Dateinamen reinzureichen, könnte man auch ein TextReader reinreichen.
    Hier mal ein Beispiel, wie so eine Klasse aussehen könnte:
    public class PersonCsvDeserializer {     private TextReader reader;     private bool isHeaderSkipped;     public PersonCsvDeserializer(TextReader reader)     {         this.reader = reader;     }     public IEnumerable<Person> Deserialize()     {         string serializedData;         while ((serializedData = this.ReadNextData()) != null)         {             Person person = this.Parse(serializedData);             yield return person;         }     }     private string ReadNextData()     {         string serializedData = this.reader.ReadLine();         if (!this.isHeaderSkipped)         {             this.isHeaderSkipped = true;             return this.ReadNextData();         }         return serializedData;     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Die Main-Methode sieht dann so aus:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);                          IEnumerable<Person> persons = deserializer.Deserialize();             foreach (Person person in persons)             {                 // ...             }         }       } } Zugegeben, in diesem Beispiel ist die Klasse PersonCsvDeserializer etwas komplizierter geworden aber es ist jetzt egal, woher die Daten stammen, solange wir ein TextReader in den Konstruktor schieben. Das reinrechen der Abhängigkeit in den Konstruktor nennt sich auch "Dependeny Injection". In diesem Beispiel habe ich auch das yield return verwendet. Da wir jetzt nur noch maximal den Speicher für ein Person-Objekt verbrauchen, könnte die Klasse eigentlich nun unendlich viele Daten deserialisieren. Ein Problem stellt aber immer noch die Indexierung des Arrays dar aber das überlasse ich jetzt dir.
    Das Interface
    Das letzte, was ich noch schreiben wollte, wäre ein geeignetes Interface für den Deserializer. Wollen wir jetzt mehrere Deserializer schreiben oder einen Deserializer als Abhängigkeit in eine Klasse reinreichen, ist ein Interface geeignet, damit es später egal ist, um welchen Deserializer es sich handelt. Man könnte sich ja auch vorstellen, dass die Daten nicht in einer CSV-Datei stecken, sondern in einer XML-Datei. Dafür wäre folgendes Interface recht nützlich
    public interface IDeserializer<T> {     IEnumerable<T> Deserialize(); } Mit diesem Interface könnten wir sogar das hässliche using im Hauptprogramm wieder loswerden. Ich finde, das using stört im Lesefluss. Wir haben ja jetzt eine Klasse, die CSV-Daten aus unterschiedlichsten Quellen von Personen deserialisieren kann. Was hindert uns nun daran, einen weiteren Deserializer zu bauen, der aus Dateien deserialisiert? Beispiel:
    public class PersonCsvFileDeserializer : IDeserializer<Person> {     private string fileName;     public PersonCsvFileDeserializer(string fileName)      {         this.fileName = fileName;     }     public IEnumerable<Person> Deserialize()     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);             return deserializer.Deserialize();         }     } } Das using wurde nach PersonCsvFileDeserializer und somit eine ebene tiefer verschoben. Wenn du Dependecy Injection verstanden hast, dann würde dir auffallen, dass die Zeile 
    PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader); eigentlich böse ist, da es eine Abhängigkeit darstellt, die wiederum in den Konstruktor gehört. Ich habe sie aber erst mal hier drinnengelassen, weil das sonst wieder bedeuten würde, dass das using wieder ins Hauptprogramm rein müsste. Eigentlich müsste man sich eine Fabrik-Methode ausdenken, die den PersonCsvFileDeserializer zusammenbaut. Die habe ich hier aber weggelassen. Die kannst du dir ja ausdenken.
    Das Hauptprogramm würde dann so aussehen:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         PersonCsvFileDeserializer deserializer = new PersonCsvFileDeserializer(fileName);                      IEnumerable<Person> persons = deserializer.Deserialize();         foreach (Person person in persons)         {             // ...         }      } } Das wäre doch schon wieder ein Schritt übersichtlicher. 
    Wie du also siehst, haben wir allein nur für das Einlesen von den CSV-Dateien drei Klassen:
    Person PersonCsvDeserializer PersonCsvFileDeserializer und ein Interface:
    IDeserializer<T> geschrieben. Man braucht also kein mega großes Projekt, um mehrere Klassen zu schreiben. Es reicht auch schon was ganz einfaches. Man sollte sich immer bewusst machen, dass Klassen immer nur eine Aufgabe machen sollten und Methoden Teilaspekte dieser Aufgabe sind und sie sollten auch nicht mehr machen, als eine Sache. Es macht auch nichts, wenn man zum Anfang Spagetticode schreibt und diesen später nach und nach einem Refactoring unterzieht. Niemand ist perfekt und niemand schreibt perfekten Code. Man fängt also immer erst mal an und arbeitet sich Schritt für Schritt an eine geeignete und saubere Lösung. Selbst meine Lösung ist mit Sicherheit nicht perfekt und ich habe auch nicht die Weisheit mit Löffeln gefressen. Wenn du mein Beitrag richtig verfolgt haben solltest, hast du vielleicht auch gemerkt, dass ich erst mal eine Lösung geschrieben habe und sie dann nach und nach verfeinert und verbessert habe. Das Wissen kommt erst mit Erfahrung und Erfahrung sammelt man nur, indem man es ausprobiert und darüber mit anderen diskutiert. Also trau dich.
    So, das reicht auch fürs erste. Ich denke, das ist erst mal genug Input.
     
  21. Like
    Whiz-zarD hat eine Reaktion von thereisnospace erhalten in Wirtschaftsinformatik Ausbildung und dann FiAE?   
    Erst mal habe ich zuvor eine betriebliche Ausbildung als Mechatroniker hinter mir. Ich kenne also das Leben als Azubi. Zweitens hatte ich im Laufe der Zeit schon einige Gesprächen mit so manchen FIAE-Azubis gehalten und irgendwie berichtet jeder von den selben Problemen. Drittens hatte ich mich mal in diesem Forum angemeldet, weil ich Informationen über die Ausbildung sammeln wollte, da ich vor habe, die Ausbildereignungsprüfung abzulegen aber in diesem Forum werden immer wieder die Dinge bestätigt, die auch zuvor die Azubis berichtet haben, mit denen ich gesprochen habe und das erschüttert mich doch sehr. 
    Das mag vielleicht sein. Das kann ich so nicht beurteilen. Ich selber war auf einer Schule in Schleswig-Holstein und diese Schule genießt in Norddeutschland einen sehr guten Ruf und die Leute, die auf dieser Schule einen Abschluss gemacht haben, werden eher genommen, als jemand mit einer betrieblichen Ausbildung.
  22. Like
    Whiz-zarD hat eine Reaktion von sas86ks erhalten in C# OOP Probleme   
    Wieso sollte man dich töten wollen?
    Softwareentwicklung ist nun mal ein Reifeprozess. Niemand liest nur ein Buch und kann gleich wunderbar sauberen Code schreiben. Mein Code sah zum Anfang auch mies aus und selbst Robert C. Martin, der das Buch "Clean Code" geschrieben hat, sagt von sich aus, dass er nicht die Weisheit mit Löffeln gefressen hat und es auch bei seinen Code-Beispielen sicherlich noch Verbesserungspotenzial gibt aber nur durch Ausprobieren lernt man. 
    Du hast schon richtig erkannt, dass man fürs Einlesen der Datei eine eigene Klasse benötigt. Allerdings gehört die Logik nicht in den Konstruktor. Der Konstruktor dient zur Initialisierung der Klasse. Der Name der Klasse sollte auch die Aufgabe widerspiegeln, was die Klasse tut. "DateiEinlesen" ist vielleicht gut, aber geht es vielleicht noch konkreter? Ich weiß, dass es eine CSV-Datei ist. Vielleicht eher CsvReader?  Wobei dieser Name auch wieder sehr allgemein ist. In der CSV-Datei steckt ja eine Tabelle. Welche Daten besitzt die Tabelle? Vielleicht kann man der Tabelle einen Namen geben. Eine CSV-Datei ist ja eine Art der Serialisierung. Das Verfahrung um so eine Tabelle in ein Objekt zu überführen, nennt man auch Deserialiserung. Das kann man ja erst mal im Hinterkopf behalten.
    Zuerst würde ich mir aber erst mal eine geeignete Datenstruktur überlegen. In der CSV-Datei stecken ja Daten. Ich nehme jetzt mal als Beispiel, dass die CSV-Datei Daten zu Personen beinhaltet:
    Name;Vorname;Geschlecht;Alter Doe;John;Maennlich;38 Also würde ich erst mal eine Klasse für diese Daten erstellen:
    public class Person {     public string Name { get; set; }     public string Vorname { get; set; }     public Geschlecht Geschlecht { get; set; }     public int Alter { get; set; } } public enum Geschlecht {     Maennlich     , Weiblich } Nun könnte ich mich darum kümmern, eine(!) Datei einzulesen. Ich habe eine Datenstruktur und ich weiß, dass ich eine CSV-Datei deserialisieren muss. Also könnte man die Klasse z.B. PersonCsvDeserializer nennen. In dieser Klasse soll es eine Methode geben, die Deserialize() heißt. Ich verzichte hier jetzt erst mal bewusst auf ein Interface, weil ich denke, dass es für dich bis hier hin schon kompliziert genug ist. Das Interface werde ich später noch mal erklären. Erst mal kümmern wir uns darum, was wir alles brauchen, um eine Datei zu deserialisieren. 
    Was muss die Klasse PersonCsvDeserializer alles wissen, um eine CSV-Datei deserialisieren zu können? Man könnte vielleicht im ersten Schritt auf die Idee kommen, dass die Klasse den Pfad und Dateinamen benötigt. Mit den Informationen aus dem letzten Absatz könnte ein erster Entwurf so aussehen: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {       // ...     } } Als Rückgabewert habe ich IEnumerable<Person> gewählt, weil IEnumerable<T> ein sehr allgemeines Interface ist und einen Enumerator (auf deutsch: Aufzählung; in anderen Sprachen auch Iterator genannt) zur Verfügung stellt, mit dem wir über die Daten iterieren können (mit der foreach-Schleife). Sowohl IList<T>, ICollection<T>, IDictionary<T>, Array und weitere Klassen implementieren dieses Interface und mehr als über die Daten iterieren wollen wir nicht. Wenn wir später damit mehr machen wollen, können wir es leicht mit Linq in eine Collection, List, Array oder auch in ein Dictionary umwandeln. Die Deserialize()-Methode soll also eine Aufzählung von Personen zurückliefern.
    Normalerweise macht man es anders, aber aus einfachheit behaupte ich mal frech, dass die erste Zeile in der CSV-Datei immer ein Header besitzt. In der Implementierung überspringe ich den Header per Linq mit der Skip()-Methode. Die Deserialize()-Methode soll also folgendes machen:
    Die Datei lesen Durch die Datenzeilen iterieren Pro Datenzeile ein Person-Objekt erstellen Die Person-Objekte als Aufzählung zurückliefern Der erste Entwurf könnte daher folgendermaßen aussehen:
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string line in File.ReadAllLines(fileName).Skip(1))         {             string[] elements = line.Split(';');             result.Add(new Person             {                 Name = elements[0],                 Vorname = elements[1],                 Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),                 Alter = Convert.ToInt32(elements[3])             });         }         return result;     } } Die Methode macht zwar was sie soll, aber ist sie wirklich übersichtlich? Nicht wirklich. Wir haben hier mehrere Ebenen miteinander vermischt. Wir können also mit dem Refactoring anfangen. z.B. das
    File.ReadAllLines(fileName).Skip(1) Wofür ist das genau gut? Wenn man den gesamten Kontext kennt, weiß man es zwar aber eigentlich liegt der Code-Abschnitt eine Ebene Tiefer. Es hantiert mit Dateien und hat mit der eigentlichen Aufgabe der Deserialiserung wenig zu tun. Also sollte man diesen Teil in eine separate Methode packen:
    private IEnumerable<string> ReadDataFromFile(string fileName) {     return File.ReadAllLines(fileName).Skip(1); } Somit wandert das Skip(1) in eine tiefere Ebene und interessiert uns in der Deserialize()-Methode nicht mehr. Als nächstes fällt aber auf, dass wir ein String mit Split() in ein Array teilen und aus diesem Array dann die einzelnen Personendaten herausfischen. Diesen Vorgang nennt man auch Parsing. Also könnten wir diesen Teil auch in eine Methode auslagern:
    private Person Parse(string serializedData) {     string[] elements = serializedData.Split(';');     return new Person     {         Name = elements[0],         Vorname = elements[1],         Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),         Alter = Convert.ToInt32(elements[3])     }; } Unsere Klasse sieht dann bis jetzt folgendermaßen aus: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string serializedData in ReadDataFromFile(fileName))         {             Person person = this.Parse(serializedData);             result.Add(person);         }         return result;     }     private IEnumerable<string> ReadDataFromFile(string fileName)     {         return File.ReadAllLines(fileName).Skip(1);     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Nun ist Deserialize() doch recht gut lesbar. Wir lesen die Daten aus der Datei, parsen die Daten und erhalten ein Person-Objekt, welches wir dann in eine Liste packen und zum Schluss geben wir die Liste zurück.
    Es gäbe hier noch weiteres Verbesserungspotenzial aber ich belasse es erst mal hierbei. Ein paar Hinweise gebe ich aber noch:
    Fehler-Handling? Was passiert, wenn z.B. die Datei nicht existiert? Ist das erzeugte Objekt List<Person> wirklich eine gute Wahl? Angenommen, wir haben es mit einer riesigen CSV-Datei (mehrere Gigabytes) zu tun, die größer ist, als unser Arbeitsspeicher. Hier schmeiße ich mal das "yield return"-Schlüsselwort in den Raum. Auch ist das indexierte Zugreifen auf das Array in der Methode Parse() nicht wirklich glücklich gelöst. Was passiert nämlich, wenn mal eine Spalte in der Datei hinzukommt? Dann muss man ja auch den Code anpassen. Das will man aber eigentlich gar nicht. Zu diskutieren wäre auch, ob die Variable fileName nicht doch besser eine Instanzvariable sein sollte, die per Konstruktor reingereicht wird. Es fällt ja auf, dass die Methoden Deserialize() und ReadDataFromFile() den Dateinamen benötigen. Also stellt fileName ja eine gewisse Abhängigkeit dar, die die Klasse benötigt, um arbeiten zu können.  Als Überlegung kannst du ja selber mal schauen, wie man mit solchen Situation umgehst.
    Um später im Hauptpgramm alle Personen zu iterieren könntest du nun folgendes schreiben:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");     PersonCsvDeserializer deserializer = new PersonCsvDeserializer();     foreach(string fileName in fileNames)     {         IEnumerable<Person> persons = deserializer.Deserialize(fileName);         foreach (Person person in persons)         {             // ...         }     } } Nach dem selben Prinzip, wie bei der PersonCsvDeserializer-Klasse kannst du ja mal überlegen, wie man nun diesen Code refactoren an.
    Ab hier wird es noch etwas technischer und tiefgreifender. Ich möchte dir noch zwei Techniken zeigen, die du aber erst mal nicht umsetzen brauchst.
    "Inversion of Control" und "Dependeny Injection"
    In der Klasse PersonCsvDeserializer fällt auf, dass die Klasse von einer Datei abhängig ist aber die Daten können vielleicht aus einer Datenbank kommen oder wir schreiben die CSV-Daten direkt in eine grafische Oberfläche. Möchte man jetzt für jeden Anwendungsfall eine eigene Klasse schreiben? Eigentlich nicht. Die Abhängigkeit zur Datei muss also aufgelöst werden. Das .Net-Framework bietet ja die abstrakte Klasse TextReader, die so ziemlich alles darstellen kann. Ein Reader, der eine Datei liest oder aus einem TCP-Stream oder aus einer Datenbank, etc. Anstatt also den Dateinamen reinzureichen, könnte man auch ein TextReader reinreichen.
    Hier mal ein Beispiel, wie so eine Klasse aussehen könnte:
    public class PersonCsvDeserializer {     private TextReader reader;     private bool isHeaderSkipped;     public PersonCsvDeserializer(TextReader reader)     {         this.reader = reader;     }     public IEnumerable<Person> Deserialize()     {         string serializedData;         while ((serializedData = this.ReadNextData()) != null)         {             Person person = this.Parse(serializedData);             yield return person;         }     }     private string ReadNextData()     {         string serializedData = this.reader.ReadLine();         if (!this.isHeaderSkipped)         {             this.isHeaderSkipped = true;             return this.ReadNextData();         }         return serializedData;     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Die Main-Methode sieht dann so aus:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);                          IEnumerable<Person> persons = deserializer.Deserialize();             foreach (Person person in persons)             {                 // ...             }         }       } } Zugegeben, in diesem Beispiel ist die Klasse PersonCsvDeserializer etwas komplizierter geworden aber es ist jetzt egal, woher die Daten stammen, solange wir ein TextReader in den Konstruktor schieben. Das reinrechen der Abhängigkeit in den Konstruktor nennt sich auch "Dependeny Injection". In diesem Beispiel habe ich auch das yield return verwendet. Da wir jetzt nur noch maximal den Speicher für ein Person-Objekt verbrauchen, könnte die Klasse eigentlich nun unendlich viele Daten deserialisieren. Ein Problem stellt aber immer noch die Indexierung des Arrays dar aber das überlasse ich jetzt dir.
    Das Interface
    Das letzte, was ich noch schreiben wollte, wäre ein geeignetes Interface für den Deserializer. Wollen wir jetzt mehrere Deserializer schreiben oder einen Deserializer als Abhängigkeit in eine Klasse reinreichen, ist ein Interface geeignet, damit es später egal ist, um welchen Deserializer es sich handelt. Man könnte sich ja auch vorstellen, dass die Daten nicht in einer CSV-Datei stecken, sondern in einer XML-Datei. Dafür wäre folgendes Interface recht nützlich
    public interface IDeserializer<T> {     IEnumerable<T> Deserialize(); } Mit diesem Interface könnten wir sogar das hässliche using im Hauptprogramm wieder loswerden. Ich finde, das using stört im Lesefluss. Wir haben ja jetzt eine Klasse, die CSV-Daten aus unterschiedlichsten Quellen von Personen deserialisieren kann. Was hindert uns nun daran, einen weiteren Deserializer zu bauen, der aus Dateien deserialisiert? Beispiel:
    public class PersonCsvFileDeserializer : IDeserializer<Person> {     private string fileName;     public PersonCsvFileDeserializer(string fileName)      {         this.fileName = fileName;     }     public IEnumerable<Person> Deserialize()     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);             return deserializer.Deserialize();         }     } } Das using wurde nach PersonCsvFileDeserializer und somit eine ebene tiefer verschoben. Wenn du Dependecy Injection verstanden hast, dann würde dir auffallen, dass die Zeile 
    PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader); eigentlich böse ist, da es eine Abhängigkeit darstellt, die wiederum in den Konstruktor gehört. Ich habe sie aber erst mal hier drinnengelassen, weil das sonst wieder bedeuten würde, dass das using wieder ins Hauptprogramm rein müsste. Eigentlich müsste man sich eine Fabrik-Methode ausdenken, die den PersonCsvFileDeserializer zusammenbaut. Die habe ich hier aber weggelassen. Die kannst du dir ja ausdenken.
    Das Hauptprogramm würde dann so aussehen:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         PersonCsvFileDeserializer deserializer = new PersonCsvFileDeserializer(fileName);                      IEnumerable<Person> persons = deserializer.Deserialize();         foreach (Person person in persons)         {             // ...         }      } } Das wäre doch schon wieder ein Schritt übersichtlicher. 
    Wie du also siehst, haben wir allein nur für das Einlesen von den CSV-Dateien drei Klassen:
    Person PersonCsvDeserializer PersonCsvFileDeserializer und ein Interface:
    IDeserializer<T> geschrieben. Man braucht also kein mega großes Projekt, um mehrere Klassen zu schreiben. Es reicht auch schon was ganz einfaches. Man sollte sich immer bewusst machen, dass Klassen immer nur eine Aufgabe machen sollten und Methoden Teilaspekte dieser Aufgabe sind und sie sollten auch nicht mehr machen, als eine Sache. Es macht auch nichts, wenn man zum Anfang Spagetticode schreibt und diesen später nach und nach einem Refactoring unterzieht. Niemand ist perfekt und niemand schreibt perfekten Code. Man fängt also immer erst mal an und arbeitet sich Schritt für Schritt an eine geeignete und saubere Lösung. Selbst meine Lösung ist mit Sicherheit nicht perfekt und ich habe auch nicht die Weisheit mit Löffeln gefressen. Wenn du mein Beitrag richtig verfolgt haben solltest, hast du vielleicht auch gemerkt, dass ich erst mal eine Lösung geschrieben habe und sie dann nach und nach verfeinert und verbessert habe. Das Wissen kommt erst mit Erfahrung und Erfahrung sammelt man nur, indem man es ausprobiert und darüber mit anderen diskutiert. Also trau dich.
    So, das reicht auch fürs erste. Ich denke, das ist erst mal genug Input.
     
  23. Like
    Whiz-zarD hat eine Reaktion von mapr erhalten in Synchronisation einer Oracle DB mit einer MySQL DB   
    Ich nehme mal an, es handelt sich um eine FIAE-Ausbildung. Wieso bildet die Firma FIAEler aus, wenn keiner programmieren kann? Was lernst du in der Firma? Vor allem von wem?
  24. Like
    Whiz-zarD reagierte auf stefan.macke in Präsentation   
    Mh... und wer sagt, dass man Sachlichkeit nicht mit Humor kombinieren darf. Warum müssen Prüfungen langweilig sein? Weil "man" das so macht? Oder weil das Gehirn langweilige Inhalte besser aufnimmt? Wenn man sein Thema beherrscht und das auch durch den Inhalt der Präsentation (ich wiederhole mich) deutlich wird, warum soll man dann nicht auch mal eine witzige Einlage bringen? Wie gesagt, es geht nicht darum, mit lustigen Folien von völliger technischer Ahnungslosigkeit abzulenken.
    Ich sage auch nicht, dass jede Folie aus animierten GIFs bestehen soll (was ich durchaus schon einmal in einem - übrigens richtig coolen - Fachvortrag gesehen habe). Man sollte vielleicht einfach das richtige Maß finden. Weder nur Text und die geforderte "Sachlichkeit", noch ausschließlich lustige Bildchen. Die gute Mischung macht's!
    Du schaust dir also ernsthaft gerne "sachliche" (ich übersetze das jetzt für mich einfach mit "langweilige") Präsentationen an, die dich nicht involvieren oder visuell stimulieren? Wenn das so ist, kann ich wenig dazu sagen. Über Geschmack kann man nicht streiten. Nur wenn ich mich auf den großen (technischen) Konferenzen da draußen umschaue, scheint die Mehrheit der Zuschauer stimuliert und inspiriert werden zu wollen. Und sollen wir unsere Azubis nicht auf das wahre Leben vorbereiten? Besteht der Alltag da draußen wirklich aus Textwüsten und humorlosen Präsentationen? Ich hoffe nicht! Und wenn doch, ist es - meiner Meinung nach - Zeit das zu ändern.
  25. Like
    Whiz-zarD hat eine Reaktion von Gooose erhalten in C# OOP Probleme   
    Wieso sollte man dich töten wollen?
    Softwareentwicklung ist nun mal ein Reifeprozess. Niemand liest nur ein Buch und kann gleich wunderbar sauberen Code schreiben. Mein Code sah zum Anfang auch mies aus und selbst Robert C. Martin, der das Buch "Clean Code" geschrieben hat, sagt von sich aus, dass er nicht die Weisheit mit Löffeln gefressen hat und es auch bei seinen Code-Beispielen sicherlich noch Verbesserungspotenzial gibt aber nur durch Ausprobieren lernt man. 
    Du hast schon richtig erkannt, dass man fürs Einlesen der Datei eine eigene Klasse benötigt. Allerdings gehört die Logik nicht in den Konstruktor. Der Konstruktor dient zur Initialisierung der Klasse. Der Name der Klasse sollte auch die Aufgabe widerspiegeln, was die Klasse tut. "DateiEinlesen" ist vielleicht gut, aber geht es vielleicht noch konkreter? Ich weiß, dass es eine CSV-Datei ist. Vielleicht eher CsvReader?  Wobei dieser Name auch wieder sehr allgemein ist. In der CSV-Datei steckt ja eine Tabelle. Welche Daten besitzt die Tabelle? Vielleicht kann man der Tabelle einen Namen geben. Eine CSV-Datei ist ja eine Art der Serialisierung. Das Verfahrung um so eine Tabelle in ein Objekt zu überführen, nennt man auch Deserialiserung. Das kann man ja erst mal im Hinterkopf behalten.
    Zuerst würde ich mir aber erst mal eine geeignete Datenstruktur überlegen. In der CSV-Datei stecken ja Daten. Ich nehme jetzt mal als Beispiel, dass die CSV-Datei Daten zu Personen beinhaltet:
    Name;Vorname;Geschlecht;Alter Doe;John;Maennlich;38 Also würde ich erst mal eine Klasse für diese Daten erstellen:
    public class Person {     public string Name { get; set; }     public string Vorname { get; set; }     public Geschlecht Geschlecht { get; set; }     public int Alter { get; set; } } public enum Geschlecht {     Maennlich     , Weiblich } Nun könnte ich mich darum kümmern, eine(!) Datei einzulesen. Ich habe eine Datenstruktur und ich weiß, dass ich eine CSV-Datei deserialisieren muss. Also könnte man die Klasse z.B. PersonCsvDeserializer nennen. In dieser Klasse soll es eine Methode geben, die Deserialize() heißt. Ich verzichte hier jetzt erst mal bewusst auf ein Interface, weil ich denke, dass es für dich bis hier hin schon kompliziert genug ist. Das Interface werde ich später noch mal erklären. Erst mal kümmern wir uns darum, was wir alles brauchen, um eine Datei zu deserialisieren. 
    Was muss die Klasse PersonCsvDeserializer alles wissen, um eine CSV-Datei deserialisieren zu können? Man könnte vielleicht im ersten Schritt auf die Idee kommen, dass die Klasse den Pfad und Dateinamen benötigt. Mit den Informationen aus dem letzten Absatz könnte ein erster Entwurf so aussehen: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {       // ...     } } Als Rückgabewert habe ich IEnumerable<Person> gewählt, weil IEnumerable<T> ein sehr allgemeines Interface ist und einen Enumerator (auf deutsch: Aufzählung; in anderen Sprachen auch Iterator genannt) zur Verfügung stellt, mit dem wir über die Daten iterieren können (mit der foreach-Schleife). Sowohl IList<T>, ICollection<T>, IDictionary<T>, Array und weitere Klassen implementieren dieses Interface und mehr als über die Daten iterieren wollen wir nicht. Wenn wir später damit mehr machen wollen, können wir es leicht mit Linq in eine Collection, List, Array oder auch in ein Dictionary umwandeln. Die Deserialize()-Methode soll also eine Aufzählung von Personen zurückliefern.
    Normalerweise macht man es anders, aber aus einfachheit behaupte ich mal frech, dass die erste Zeile in der CSV-Datei immer ein Header besitzt. In der Implementierung überspringe ich den Header per Linq mit der Skip()-Methode. Die Deserialize()-Methode soll also folgendes machen:
    Die Datei lesen Durch die Datenzeilen iterieren Pro Datenzeile ein Person-Objekt erstellen Die Person-Objekte als Aufzählung zurückliefern Der erste Entwurf könnte daher folgendermaßen aussehen:
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string line in File.ReadAllLines(fileName).Skip(1))         {             string[] elements = line.Split(';');             result.Add(new Person             {                 Name = elements[0],                 Vorname = elements[1],                 Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),                 Alter = Convert.ToInt32(elements[3])             });         }         return result;     } } Die Methode macht zwar was sie soll, aber ist sie wirklich übersichtlich? Nicht wirklich. Wir haben hier mehrere Ebenen miteinander vermischt. Wir können also mit dem Refactoring anfangen. z.B. das
    File.ReadAllLines(fileName).Skip(1) Wofür ist das genau gut? Wenn man den gesamten Kontext kennt, weiß man es zwar aber eigentlich liegt der Code-Abschnitt eine Ebene Tiefer. Es hantiert mit Dateien und hat mit der eigentlichen Aufgabe der Deserialiserung wenig zu tun. Also sollte man diesen Teil in eine separate Methode packen:
    private IEnumerable<string> ReadDataFromFile(string fileName) {     return File.ReadAllLines(fileName).Skip(1); } Somit wandert das Skip(1) in eine tiefere Ebene und interessiert uns in der Deserialize()-Methode nicht mehr. Als nächstes fällt aber auf, dass wir ein String mit Split() in ein Array teilen und aus diesem Array dann die einzelnen Personendaten herausfischen. Diesen Vorgang nennt man auch Parsing. Also könnten wir diesen Teil auch in eine Methode auslagern:
    private Person Parse(string serializedData) {     string[] elements = serializedData.Split(';');     return new Person     {         Name = elements[0],         Vorname = elements[1],         Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),         Alter = Convert.ToInt32(elements[3])     }; } Unsere Klasse sieht dann bis jetzt folgendermaßen aus: 
    public class PersonCsvDeserializer {     public IEnumerable<Person> Deserialize(string fileName)     {         IList<Person> result = new List<Person>();         foreach (string serializedData in ReadDataFromFile(fileName))         {             Person person = this.Parse(serializedData);             result.Add(person);         }         return result;     }     private IEnumerable<string> ReadDataFromFile(string fileName)     {         return File.ReadAllLines(fileName).Skip(1);     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Nun ist Deserialize() doch recht gut lesbar. Wir lesen die Daten aus der Datei, parsen die Daten und erhalten ein Person-Objekt, welches wir dann in eine Liste packen und zum Schluss geben wir die Liste zurück.
    Es gäbe hier noch weiteres Verbesserungspotenzial aber ich belasse es erst mal hierbei. Ein paar Hinweise gebe ich aber noch:
    Fehler-Handling? Was passiert, wenn z.B. die Datei nicht existiert? Ist das erzeugte Objekt List<Person> wirklich eine gute Wahl? Angenommen, wir haben es mit einer riesigen CSV-Datei (mehrere Gigabytes) zu tun, die größer ist, als unser Arbeitsspeicher. Hier schmeiße ich mal das "yield return"-Schlüsselwort in den Raum. Auch ist das indexierte Zugreifen auf das Array in der Methode Parse() nicht wirklich glücklich gelöst. Was passiert nämlich, wenn mal eine Spalte in der Datei hinzukommt? Dann muss man ja auch den Code anpassen. Das will man aber eigentlich gar nicht. Zu diskutieren wäre auch, ob die Variable fileName nicht doch besser eine Instanzvariable sein sollte, die per Konstruktor reingereicht wird. Es fällt ja auf, dass die Methoden Deserialize() und ReadDataFromFile() den Dateinamen benötigen. Also stellt fileName ja eine gewisse Abhängigkeit dar, die die Klasse benötigt, um arbeiten zu können.  Als Überlegung kannst du ja selber mal schauen, wie man mit solchen Situation umgehst.
    Um später im Hauptpgramm alle Personen zu iterieren könntest du nun folgendes schreiben:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");     PersonCsvDeserializer deserializer = new PersonCsvDeserializer();     foreach(string fileName in fileNames)     {         IEnumerable<Person> persons = deserializer.Deserialize(fileName);         foreach (Person person in persons)         {             // ...         }     } } Nach dem selben Prinzip, wie bei der PersonCsvDeserializer-Klasse kannst du ja mal überlegen, wie man nun diesen Code refactoren an.
    Ab hier wird es noch etwas technischer und tiefgreifender. Ich möchte dir noch zwei Techniken zeigen, die du aber erst mal nicht umsetzen brauchst.
    "Inversion of Control" und "Dependeny Injection"
    In der Klasse PersonCsvDeserializer fällt auf, dass die Klasse von einer Datei abhängig ist aber die Daten können vielleicht aus einer Datenbank kommen oder wir schreiben die CSV-Daten direkt in eine grafische Oberfläche. Möchte man jetzt für jeden Anwendungsfall eine eigene Klasse schreiben? Eigentlich nicht. Die Abhängigkeit zur Datei muss also aufgelöst werden. Das .Net-Framework bietet ja die abstrakte Klasse TextReader, die so ziemlich alles darstellen kann. Ein Reader, der eine Datei liest oder aus einem TCP-Stream oder aus einer Datenbank, etc. Anstatt also den Dateinamen reinzureichen, könnte man auch ein TextReader reinreichen.
    Hier mal ein Beispiel, wie so eine Klasse aussehen könnte:
    public class PersonCsvDeserializer {     private TextReader reader;     private bool isHeaderSkipped;     public PersonCsvDeserializer(TextReader reader)     {         this.reader = reader;     }     public IEnumerable<Person> Deserialize()     {         string serializedData;         while ((serializedData = this.ReadNextData()) != null)         {             Person person = this.Parse(serializedData);             yield return person;         }     }     private string ReadNextData()     {         string serializedData = this.reader.ReadLine();         if (!this.isHeaderSkipped)         {             this.isHeaderSkipped = true;             return this.ReadNextData();         }         return serializedData;     }     private Person Parse(string serializedData)     {         string[] elements = serializedData.Split(';');         return new Person         {             Name = elements[0],             Vorname = elements[1],             Geschlecht = (Geschlecht)Enum.Parse(typeof(Geschlecht), elements[2]),             Alter = Convert.ToInt32(elements[3])         };     } } Die Main-Methode sieht dann so aus:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);                          IEnumerable<Person> persons = deserializer.Deserialize();             foreach (Person person in persons)             {                 // ...             }         }       } } Zugegeben, in diesem Beispiel ist die Klasse PersonCsvDeserializer etwas komplizierter geworden aber es ist jetzt egal, woher die Daten stammen, solange wir ein TextReader in den Konstruktor schieben. Das reinrechen der Abhängigkeit in den Konstruktor nennt sich auch "Dependeny Injection". In diesem Beispiel habe ich auch das yield return verwendet. Da wir jetzt nur noch maximal den Speicher für ein Person-Objekt verbrauchen, könnte die Klasse eigentlich nun unendlich viele Daten deserialisieren. Ein Problem stellt aber immer noch die Indexierung des Arrays dar aber das überlasse ich jetzt dir.
    Das Interface
    Das letzte, was ich noch schreiben wollte, wäre ein geeignetes Interface für den Deserializer. Wollen wir jetzt mehrere Deserializer schreiben oder einen Deserializer als Abhängigkeit in eine Klasse reinreichen, ist ein Interface geeignet, damit es später egal ist, um welchen Deserializer es sich handelt. Man könnte sich ja auch vorstellen, dass die Daten nicht in einer CSV-Datei stecken, sondern in einer XML-Datei. Dafür wäre folgendes Interface recht nützlich
    public interface IDeserializer<T> {     IEnumerable<T> Deserialize(); } Mit diesem Interface könnten wir sogar das hässliche using im Hauptprogramm wieder loswerden. Ich finde, das using stört im Lesefluss. Wir haben ja jetzt eine Klasse, die CSV-Daten aus unterschiedlichsten Quellen von Personen deserialisieren kann. Was hindert uns nun daran, einen weiteren Deserializer zu bauen, der aus Dateien deserialisiert? Beispiel:
    public class PersonCsvFileDeserializer : IDeserializer<Person> {     private string fileName;     public PersonCsvFileDeserializer(string fileName)      {         this.fileName = fileName;     }     public IEnumerable<Person> Deserialize()     {         using (TextReader reader = File.OpenText(fileName))         {             PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader);             return deserializer.Deserialize();         }     } } Das using wurde nach PersonCsvFileDeserializer und somit eine ebene tiefer verschoben. Wenn du Dependecy Injection verstanden hast, dann würde dir auffallen, dass die Zeile 
    PersonCsvDeserializer deserializer = new PersonCsvDeserializer(reader); eigentlich böse ist, da es eine Abhängigkeit darstellt, die wiederum in den Konstruktor gehört. Ich habe sie aber erst mal hier drinnengelassen, weil das sonst wieder bedeuten würde, dass das using wieder ins Hauptprogramm rein müsste. Eigentlich müsste man sich eine Fabrik-Methode ausdenken, die den PersonCsvFileDeserializer zusammenbaut. Die habe ich hier aber weggelassen. Die kannst du dir ja ausdenken.
    Das Hauptprogramm würde dann so aussehen:
    static void Main(string[] args) {     string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";     IEnumerable<string> fileNames = Directory.GetFiles(rootPath, "*.csv");          foreach(string fileName in fileNames)     {         PersonCsvFileDeserializer deserializer = new PersonCsvFileDeserializer(fileName);                      IEnumerable<Person> persons = deserializer.Deserialize();         foreach (Person person in persons)         {             // ...         }      } } Das wäre doch schon wieder ein Schritt übersichtlicher. 
    Wie du also siehst, haben wir allein nur für das Einlesen von den CSV-Dateien drei Klassen:
    Person PersonCsvDeserializer PersonCsvFileDeserializer und ein Interface:
    IDeserializer<T> geschrieben. Man braucht also kein mega großes Projekt, um mehrere Klassen zu schreiben. Es reicht auch schon was ganz einfaches. Man sollte sich immer bewusst machen, dass Klassen immer nur eine Aufgabe machen sollten und Methoden Teilaspekte dieser Aufgabe sind und sie sollten auch nicht mehr machen, als eine Sache. Es macht auch nichts, wenn man zum Anfang Spagetticode schreibt und diesen später nach und nach einem Refactoring unterzieht. Niemand ist perfekt und niemand schreibt perfekten Code. Man fängt also immer erst mal an und arbeitet sich Schritt für Schritt an eine geeignete und saubere Lösung. Selbst meine Lösung ist mit Sicherheit nicht perfekt und ich habe auch nicht die Weisheit mit Löffeln gefressen. Wenn du mein Beitrag richtig verfolgt haben solltest, hast du vielleicht auch gemerkt, dass ich erst mal eine Lösung geschrieben habe und sie dann nach und nach verfeinert und verbessert habe. Das Wissen kommt erst mit Erfahrung und Erfahrung sammelt man nur, indem man es ausprobiert und darüber mit anderen diskutiert. Also trau dich.
    So, das reicht auch fürs erste. Ich denke, das ist erst mal genug Input.
     

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...