Entwickler-Ecke
Basistechnologien - extra Klasse?
ottto - Mo 08.12.14 19:26
Titel: extra Klasse?
Hallo,
ich bin Neuling in der Welt der objektorientierten Programmierung. Nachdem ich nun ein Grundlagenbuch durchgearbeitet hab, tue ich mich immer noch schwer objektorientiert zu "denken". In folgendem Beispiel werden die CSV-Dateien in einem Verzeichnis ausgelesen, einzelne Werte selektiert und in eine neue Datei geschrieben. Später sollen noch Werte aus der Quelldatei verglichen bzw. verrechnet werden. E/A -Ausnahmen wurden auch noch nicht berücksichtigt.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| class Program { static void Main(string[] args) { string qPfad = @"C:\Ablage"; string zPfad = @"C:\Ablage\Ziel"; DirectoryInfo verz1 = new DirectoryInfo(qPfad); foreach (FileInfo f in verz1.GetFiles("*.CSV")) { Console.WriteLine(f.FullName); string dateiInhalt = File.ReadAllText(f.FullName); string[] arrDateiInhalt = dateiInhalt.Split(';'); string zDatName = f.FullName.Insert(f.FullName.IndexOf(".csv"), "_neu"); zDatName = zDatName.Replace(qPfad, zPfad); Console.WriteLine(zDatName); File.WriteAllText(zDatName, (arrDateiInhalt[3] + ";" + arrDateiInhalt[1] + ";")); } Console.ReadKey(); } } |
Bisher sieht mein Programm immer noch "prozedural" aus. Sollte an der Stelle Logik in Klassen/Methoden ausgelagert werden? kann mir mal bitte jemand einen Schups geben?
Danke.
ottto
Moderiert von
Th69: Quote- durch C#-Tags ersetzt
Th69 - Mo 08.12.14 20:05
Hallo,
der erste Schritt wäre, daraus eine Methode zu erstellen, welche die beiden Pfade als Parameter enthält.
Und anschließend kannst du diese Methode dann in eine eigene Klasse (und am besten in einer eigenen Datei) auslagern.
Das Visual Studio kann dir sogar beim Erstellen der Methode helfen, indem du die entsprechenden Codezeilen selektierst und dann im Kontextmenü
Extract Method [
http://msdn.microsoft.com/en-us/library/0s21cwxk.aspx] (bzw. auf deutsch
Methode extrahieren [
http://msdn.microsoft.com/de-de/library/0s21cwxk.aspx]) auswählst.
Damit du aber lernst, wie man Methoden erzeugt, solltest du es einmal selber von Hand machen (aber beim weiteren Programmieren kann der Menüpunkt sehr hilfreich sein, da auch automatisch die Parameter erzeugt werden).
Ralf Jansen - Mo 08.12.14 20:58
Ein zentraler Punkt der vielleicht hilft in die ~richtige~ Richtung zu denken ist insbesondere Wiederverwendbarkeit zu berücksichtigen. Du hast jetzt einen Einmalcode geschrieben der genau einen bestimmten Spezialfall abdeckt. Du kannst nicht einen Teil deines Codes nehmen und in anderem Context wiederverwenden. Insbesondere nicht so das du eine gewisse Sicherheit hast das er auch funktioniert ohne es genau zu testen.
Um etwas wiederzuverwenden brauchst du einen scharf abgrenzbare einzelne Aufgabe die dieser Baustein (also z.B eine Klasse) löst. Bei deinen Stück Code müsstest du dir also überlegen welcher Teilaufgaben muss ich lösen (Datei in Format xyz einlesen, Daten verarbeiten, Daten als Datei in Format abc wegschreiben etc.). Als nächsten Schritt überlegst du dir dann welche dieser Teilaufgaben werde ich wohl in Zukunft so oder ähnlich immer wieder mal lösen müssen und welche Teile sind eigentlich so speziell das die nur in diesem konkreten Fall hilfreich sind. Ersteres wären also Kandidaten für eigene Klassen/Methoden und 2.teres eher die Gluelogik die die Klassen zu einen Programm zusammenführt.
Ein Beispiel, bei dir ist doch eindeutig das das CSV lesen und schreiben ein wiederverwendbarer Baustein ist. Damit er wiederverwendbar wird musst du dann überlegen welche Eigenschaften sind fix und welche Variable. Umgesetzt in eine Klasse hieße das dann du musst der irgendwie den Pfad zur Datei zukommen lassen und das gewünschte Trennzeichen einstellen können (und dann irgendwann vielleicht weitere Dinge wie Quotings etc.). Damit man die eingelesen Daten auch irgendwie bearbeiten kann, wenn wir wieder an Wiederverwendbarkeit denken so das die austauschbar wäre ohne das Funktionieren des Rests zu gefährden, brauchst du eine Datenstruktur an die die die Bearbeitung einfach dranschrauben kannst. Das kann erstmal ein string Array sein je nachdem was du dir als Bearbeitung der Daten vorgestellt hast kann das aber zu knapp sein. Das wäre hier also möglicherweise eine 2.te Klasse. Ergo hättest du am Ende eine Klasse/Methode die ein CSV einlesen kann und ein bearbeitbare Datenstruktur (eigene Klasse) zurückliefert und eine Klasse/Methode (könnte auch eine andere Methode der zuerst genannten Klasse sein) die die Datenstruktur entgegennimmt und in ein Datei wegschreibt.
ottto - Do 11.12.14 17:05
Hallo,
und vielen Dank für Eure hilfreichen Antworten!
Anbei meine objektorientierter Ansatz bei dem auch die Wiederverwendbarkeit berücksichtigt wurde.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| namespace CSV { class Program { static void Main(string[] args) { string qPfad = @"C:\Ablage"; string zPfad = @"C:\Ablage\Ziel";
CSV_read_write csv_r_w = new CSV_read_write(); csv_r_w.qPfad = qPfad; csv_r_w.zPfad = zPfad; DirectoryInfo qVerz = new DirectoryInfo(qPfad); foreach (FileInfo f in qVerz.GetFiles("*.CSV")) { csv_r_w.qDatName = f.FullName; string rueckgabe = csv_r_w.Lesen(); string zAusgabe = ("Testausgabe: " + rueckgabe); csv_r_w.Schreiben(zAusgabe); } Console.ReadKey(); } } } |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| namespace CSV { class CSV_read_write { public string qPfad { get; set; } public string zPfad { get; set; } public string qDatName { get; set; }
public string Lesen() { string dateiInhalt = File.ReadAllText(qDatName); string[] arrDateiInhalt = dateiInhalt.Split(';'); return (arrDateiInhalt[1]); } public void Schreiben(string text) { string zDatName = qDatName.Insert(qDatName.IndexOf(".csv"), "_neu"); zDatName = zDatName.Replace(qPfad, zPfad); Console.WriteLine(zDatName); File.WriteAllText(zDatName, text); } } } |
Ich würde gern das komplette Array "arrDateiInhalt" aus der Methode Lesen übergeben, so dass ich beliebige Arrayinhalte in meiner Main bearbeiten könnte. Das gelingt mir leider nicht. Gibt es da eine Möglichkeit oder bin ich auf dem Holzweg?
Danke.
Gruß.
ottto
OlafSt - Do 11.12.14 17:17
ein simples
C#-Quelltext
1:
| public string[] Lesen() |
funktioniert nicht ?
Th69 - Do 11.12.14 17:17
Ja, das geht ganz einfach. Ändere den Rückgabetyp auf string[] und gib direkt arrDateiInhalt zurück.
Ralf Jansen - Do 11.12.14 17:18
C#-Quelltext
1: 2: 3: 4: 5:
| public string[] Lesen() { ..... return arrDateiInhalt; } |
Zum Stil. Ich würde den jeweiligen Pfad der Lesen/Schreiben Methode übergeben und nicht als Properties veröffentliche. Das "_neu" dranfummeln ist dann auch eher was für den Aufrufer der Klasse. Ein belibieger Nutzer deiner Klasse möchte ja nicht unbedingt da "_neu" stehen haben. Als Properties eignet sich eher sowas wie der Separator (das Semikolon). Im Konstruktor kannst du ja für diese Property erstmal das Semikolon setzen damit man die nur benutzen muß wenn man was anderes als das Semikolon will.
Edit: Haben deine Dateien nur eine Datenzeile? Dein String.Split auf den gesamten Dateiinhalt wird nicht richtig mit Zeilenumbrüchen umgehen können. Bei mehreren Datenzeilen hättest du dann auch eher ein 2-D Array (string[][]).
ottto - Do 11.12.14 17:40
Da hab ich wohl den Wald vor lauter Bäumen nicht gesehen. -> Funktioniert.
@Ralf: Die Dateien haben nur eine Zeile. Deine Anregungen werde ich noch einarbeiten.
Vielen Dank für die schnelle Hilfe!!!
Gruß.
ottto
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!