Zum Inhalt springen
  • 0

C# OOP Probleme


Tician

Frage

Moin,

Wie versprochen versuche ich mich and er OOP um mir den Spaghetti-Code abzugewöhnen. Tötet mich nicht das ist mein erstes Mal und die Chancen bestehen das ich weit am Ziel vorbei geschossen bin. Folgenden Code mit 2 Klassen habe ich:

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string sourcePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\blabla";
                string searchPattern = "*.csv";
                int spalte = 7;

                //lesen
                DateiEinlesen datei = new DateiEinlesen(sourcePath, searchPattern, spalte);
                Console.WriteLine("Dateien eingelesen");
            }
            catch
            {

            }
        }
    }


class DateiEinlesen
    {
        string sourcePath;
        string searchPattern;
        int spalte;
        public DateiEinlesen(string sourcePath, string searchPattern, int spalte)
        {
            try
            {
                this.sourcePath = sourcePath;
                this.searchPattern = searchPattern;
                this.spalte = spalte;

                string currentLine;
                string[] fileArray = Directory.GetFiles(sourcePath, searchPattern);
                string[] lineData;
                int sourcearrayLength = fileArray.Length;
                Console.WriteLine(sourcearrayLength + " Dateien gefunden!");
                List<string>[,] liste = new List<string>[sourcearrayLength,2]; //liste für jede Datei[NummerDerDatei,Zeilen[1]/AusgewählteSpalte[2]]

                if (sourcearrayLength == 0)
                {
                    Environment.Exit(0);
                }

                for (int x = 1; x <= sourcearrayLength; x++) //jede Datei
                {
                    using (StreamReader sr = new StreamReader(sourcePath))
                    {
                        liste[x - 1, 0].Add(sr.ReadLine());

                        while ((currentLine = sr.ReadLine()) != null)
                        {
                            liste[x - 1, 0].Add(currentLine);
                            lineData = currentLine.Split(';');
                            liste[x - 1, 1].Add(lineData[spalte - 1]);
                        }
                        sr.Close();
                    }
                }                
            }
            catch (Exception ex) 
            {
                //sr.Close(); //Sichtbarkeit?!
                Console.WriteLine(ex);
            }            
        }
    }

Das Programm soll csv-Dateien in einem Ordner einlesen. Pro Datei soll es jeweils 2 Listen geben, eine mit den ganzen zeilen und eine nur mit einer bestimmten Spalte jeder Zeile.

1. Problem: Ich weiß wie ich über den Konstruktor Variablen von meiner Main-Klasse in die andere Klasse zum benutzen weitergeben kann. Ich hab absolut null Ahnung oder Erfahrung wie ich meine 2-dimensionale Liste zurück an meine Main-Klasse geben kann um sie dort für weitere Zwecke zu benutzen (später an eine weitere Klasse zu übergeben).

Ich habe versucht mich zu belesen, aber ich versteh das get/set Zeug ums verrecken nicht.

2. Problem: der StreamReader sollte (wenn ich das richtig verstanden habe) auch bei einer Exception ein Close() bekommen, das ist mir aber hier nicht so möglich wie ich es wollte. Wie machen andere das?

Könnte mir jemand auf die Sprünge helfen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Empfohlene Beiträge

  • 4
vor 22 Stunden schrieb Tician:

Tötet mich nicht das ist mein erstes Mal und die Chancen bestehen das ich weit am Ziel vorbei geschossen bin.

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. :)

 

Bearbeitet von Whiz-zarD
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1

Die Frage ist, wie sollen wir dir nun helfen?
Ich kann dir die erste Frage in deinem ersten Post beantworten. Die Frage ist dann aber, ob du das überhaupt verstehst.

Und das führt mich zu folgendes:

Am 4.1.2017 um 15:57 schrieb Tician:

Ich kann programmieren, ob es gut ist ist eine andere Frage.

Ich behaupte mal frech: Nein, du kannst es nicht. Zumindest noch nicht.
Programmieren ist mehr, als nur ein paar Zeilen Code zu schreiben, die man nicht versteht. Das du den Code selber nicht verstehst, sieht man daran, dass du Kommentare brauchst, um den Code zu erklären, damit du noch am nächsten Tag weißt, was der überhaupt macht. Ich sehe hier zwei große Probleme, die du erstmal in den Griff bekommen müsstest, um weiterkommen zu können:

  1. Du musst die Objektorientierung verstehen
  2. Du musst das Konzept bzw. die Syntax von C# verstehen

Dir ist offenbar nicht klar, dass Klassen aus Methoden und Eigenschaften bestehen.

Zugriffsmodifizierer

In C# kann man mit Hilfe der Zugriffsmodifizierer die Sichtbarkeit der Methoden und Eigenschaften bestimmen:

  • public: Die Methode/Eigenschaft ist von außen sichtbar
  • private: Die Methode/Eigenschaft steht nur der direkten Klasse zur Verfügung; sie ist von außen nicht sichtbar
  • protected: Die Methode/Eigeschaft steht der direkten und vererbten Klasse zur Verfügung; sie ist von außen nicht sichtbar
  • internal: Die Methode/Eigenschaft steht nur im eigenen Projekt zur Verfügung.

internal ist mehr ein Sonderling und kommt in der Praxis relativ selten vor. Es wird oft verwendet, wenn man private Klassen in einem Unittest testen möchte, da man die Möglichkeit besitzt, den Zugriff auf solche Klassen dennoch in anderen Projekten zu erlauben. Dies muss man aber explizit in der Projekt-Datei angeben.

Eigenschaften

Eigenschaften lassen sich über get abrufen und über set setzen. Eigenschaften definiert man wie folgt:

class A
{
    public int Nummer { get; set; }
}

Bei dieser Art der Implementierung einer Eigenschaft spricht man auch von einer "automatisch implementierten Eigenschaft", da der C#-Kompiler dahergeht und Standard-Getter- und Setter-Methoden generiert, da der getter- und setter nicht ausprogrammiert worden sind. Der Kompiler generiert daraus folgenden Code:

class A
{
    private int nummer;

    public int get_Nummer()
    {
        return this.nummer;
    }

    public void set_Nummer(int value)
    {
        this.nummer = value;
    }
}

Wie man sehen kann, wird dann ein privates Feld und eine öffentliche get- und set-Methode generiert, mit denen man das Feld von außen steuern kann. Natürlich kann man auch hier die Sichtbarkeit einschränken. Beispiel:

class A
{
    public int Nummer { get; private set; }
}

Der Getter ist dann öffentlich (public) und der Setter ist nicht öffentlich (private). Natürlich kann man auch das public gegen einen anderen Modifizierer ersetzen:

class A
{
    protected int Nummer { get; set; }
}

In diesem Beispiel ist der Getter- und Setter protected. Also nur in der direkten und vererbten Klasse sichtbar und von außen nicht.

Man kann auch selbst den Getter- und Setter implementieren, wenn man möchte, dass noch zusätzlich was passiert. Häufig ist dies der Fall, wenn man ein Event auslösen möchte, wenn eine Eigenschaft sich ändert. Dann muss man auf die automatische Implementierung der Standard Getter- und Setter-Methoden verzichten und es selbst schreiben: Beispiel:

public class A
{
    private int nummer;

    public int Nummer
    {
        get
        {
            return this.nummer;
        }
        set
        {
            Console.WriteLine("Nummer gesetzt auf {0}", value)
            this.nummer = value;
        }
    }
}

In diesem Beispiel wird auf der Konsole der neue Wert für Nummer ausgegeben. In der Set-Methode steht die Variable value zur Verfügung, die den neuen Wert besitzt. Der Kompiler würde daraus folgenden Code erzeugen:

class A
{
    private int nummer;

    public int get_Nummer()
    {
        return this.nummer;
    }

    public void set_Nummer(int value)
    {
        Console.WriteLine("Nummer gesetzt auf {0}", value)
        this.nummer = value;
    }
}

Die Schreibweise mit get {...} und set {...} ist also nichts weiter als syntaktischer Zucker, um den Code kompakter zu machen. Daraus werden dann auch nur Methoden generiert.

Methoden

Methoden können einen Rückgabewert besitzen oder nicht. Wie man schon beim generierten Getter- und Setter-Methoden der Eigenschaften sehen kann, gibt ein void an, dass die Methode kein Rückgabewert besitzt. Ersetzt man void hingegen gegen einen Datentyp, so gibt die Methode einen Wert vom genannten Datentyp zurück. Beispiel:

public string GetHallo()
{
    return "Hallo";
}

Die Methode GetHallo() gibt den String "Hallo" zurück.

Zu deiner ursprünglichen zweiten Frage:

Am 30.12.2016 um 15:52 schrieb Tician:

2. Problem: der StreamReader sollte (wenn ich das richtig verstanden habe) auch bei einer Exception ein Close() bekommen, das ist mir aber hier nicht so möglich wie ich es wollte. Wie machen andere das?

Ich habe mir mal den Code vom StreamReader angeschaut. Die Dispose()-Methode ruft Close() auf.
Sprich, wenn du um den StreamReader ein using machst, wird automatisch Close() aufgerufen, wenn Dispose() aufgerufen wird.

Hier mache ich aber auch erst mal schluss, da ich nicht weiß, ob du überhaupt verstehst, was ich hier geschrieben habe. Wenn du es verstanden haben solltest, kann ich noch was zu Klassen und Generics schreiben.

Bearbeitet von Whiz-zarD
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1
vor einer Stunde schrieb Tician:

Würde es dann in Klasse B so aussehen?

Nein. Eigenschaft werden wie Member benutzt:

A.Nummer = 15;
int zahl = A.Nummer;

 

vor einer Stunde schrieb Tician:

Ich habe das schon öfter gesehen aber warum benutzt man das?

Weil es viel flexibler ist.

Such mal nach String.Format, das ist die Methode, die hier eigentlich zum Einsatz kommt. WriteLine leitet das nur weiter.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1
vor 1 Stunde schrieb Klotzkopp:

Nein. Eigenschaft werden wie Member benutzt:


A.Nummer = 15;
int zahl = A.Nummer;

 

Genau.
Der Entwickler benutzt es wie Members. Der Kompiler macht daraus später Methodenaufrufe.

vor 3 Stunden schrieb Tician:

 


Console.WriteLine("Nummer gesetzt auf {0}", value)

Ich habe das schon öfter gesehen aber warum benutzt man das? Warum nicht so:


Console.WriteLine("Nummer gesetzt auf " + value)

Was machen die geschweiften Klammern mit der null da?

WriteLine besitzt weitere Signaturen. Darunter auch eine Signatur, die der String.Format()-Methode entspricht.
Die {0} ist ein Platzhalter und wird gegen den ersten parameter - also value - ausgetauscht. Strings zu konkatenieren (mit dem +-Operator zusammenfügen) sollte man vermeiden, Das liegt an der Eigenheit der Strings. Strings sind immutable. D.h. unveränderbar. Der +-Operator nimmt die Werte und baut daraus einen neuen String. In diesem Fall macht es wenig Probleme aber stelle dir mal vor, du führst dies mehrere Tausend mal hintereinander aus. Dann wird das irgendwann sehr langsam, weil jedes Mal ein neuer String gebaut wird. Darum gibt es z.B. die String.Format()-Methode und die StringBuilder-Klasse, um Strings zu generieren, ohne dass jedes Mal zwischendurch ein neuer String gebaut werden muss. 

Mit dem neuen C# 6.0 gibt es inzwischen auch eine weitere lesbarere Variante:

Console.WriteLine($"Nummer gesetzt auf {value}");

Diese Variante nennt sich String Interpolation
Die String Interpolation beginnt mit einem $-Zeichen. Danach werden die Variablen, die ausgewiesen werden sollen, in geschweifte Klammern gesetzt. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1
vor 45 Minuten schrieb Tician:

Naja so haben wir es gelernt... unser Lehrer im ersten Lehrjahr war Java-Programmierer, die Schüler fanden ihn gut aber er war eben nur ein Jahr lang da und das ist was wir beigebracht bekommen haben.

http://wierbicki.de/programmierung-c/

Der Lehrer selbst musste sich in C# einarbeiten. Das sind unsere Materialien aus dem ersten Lehrjahr nur mittlerweile habe ich so angst zu hören "Habt ihr doch gelernt" und ich kann es einfach nicht anwenden. :unsure:

Die Folien sind aus meiner Sicht totale Grütze ...
Die kann man vielleicht in der 7. Klasse verwenden, damit die Schüler ein bisschen Spaß haben können aber für Azubis sollte da schon mehr Niveau sein. Wo ist Vererbung? Polymorphie? Generics?

Sorry, aber ihr lernt nicht mal Ansatzweise Objektorientierung. Geschweige denn richtig mit C# umzugehen. Auch wenn er aus der Java-Welt kommen sollte, hat er dennoch nicht das Zeug dazu, echt das richtig beizubringen. Java unterscheidet sich von C# nicht so sonderlich viel.

vor 52 Minuten schrieb Tician:

Der Rest mit den typischen Fehlern war für komplette Anfänger sehr hilfreich, in Klassenarbeiten mussten wir Fehler in vorgefertigtem Code finden (auf dem Blatt Papier natürlich). Klammern die gefehlt haben, Semikolon die vergessen wurden, Anführungszeichen bei strings und vieles mehr.

Meiner Meinung nach ist das Bullshit. Wenn man die Syntax richtig erklären würde, dann würde man auch das Konzept hinter der Syntax verstehen und dann lösen sich Syntax-Fehler von alleine. Man braucht da nicht irgendwelche Regeln auswendig lernen. Die kommen von alleine, wenn man einmal die Syntax verstanden hat... 

Aber Gut zum Thema:

vor 54 Minuten schrieb Tician:

Zurück zum Thema: Wenn ich Getter und Setter explizit schreibe dann rufe ich es wie eine Methode auf? Du hast ja oben slebst ein Beispiel gezeigt wie der Compiler es übersetzen würde, das sieht mir jetzt wie das aus was wir gelernt haben - oder? Im Prinzip werden ich zukünftig wohl sowieso nur noch mit dem {get; set} arbeiten schätze ich.

Ja, das ist richtig. C# verfolgt aber das Ziel Daten grundsätzlich mit einem Zuweisungsoperator zu manipulieren, während Methoden eine Aufgabe darstellt, die mit den Daten arbeitet. Wenn man, wie in der Java-Welt, Getter- und Setter-Methoden schreiben würde, würde man die Manipulation von Daten und Methoden vermischen und somit hätte man kein gleichmäßiges Bild mehr. Darum abstrahiert C# die Getter- und Setter-Methoden. 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1
vor einer Stunde schrieb Whiz-zarD:

Die Folien sind aus meiner Sicht totale Grütze ...
Die kann man vielleicht in der 7. Klasse verwenden, damit die Schüler ein bisschen Spaß haben können aber für Azubis sollte da schon mehr Niveau sein. Wo ist Vererbung? Polymorphie? Generics?

Sorry, aber ihr lernt nicht mal Ansatzweise Objektorientierung. Geschweige denn richtig mit C# umzugehen. Auch wenn er aus der Java-Welt kommen sollte, hat er dennoch nicht das Zeug dazu, echt das richtig beizubringen. Java unterscheidet sich von C# nicht so sonderlich viel.

Ich kann echt nur immer wieder den Kopf schütteln.

Beachtest du auch welcher Umfang da überhaupt vermittelt werden soll, über welche (geringe) Dauer und von welchem Startpunkt aus? Soll man auch das Wort Aushilfslehrer mal fett hervorheben?

Die Schüler fangen da bei Null an. Dort sind Folien für 18 Unterrichtseinheiten, die ersten beiden beschäftigen sich mit dem Kennenlernen der Personen und der organisatorischen Gegebenheiten seines Unterrichts.

Dann ist der Abstand zwischen dein einzelnen Einheiten recht groß, da muss der Lehrer die Schüler erst einmal wieder abholen bevor er an der gleichen Stelle vom letzten mal fortsetzen kann - oder er verlässt sich drauf, dass die Schüler alleine weiter gemacht haben oder ein anderer Lehrer seine Ideen fortgesetzt hat, good luck bro.

Es müssen Übungsaufgaben untergebracht werden damit das gelernte ein bisschen gefestigt wird bevor die nächsten Konzepte gelehrt werden.

Ich kapier nicht, wie du scheinbar so unglaublich verständnislos gegenüber den Ausbildern und Lehrern stehst. Weiß du eigentlich, dass da auch die schlechteren Schüler mitgenommen werden sollen? Da kann man einfach nicht so schnell machen.

Ich kann mir übrigens auch nicht vorstellen, dass diese einzelnen Unterrichtseinheiten ganze Tage darstellen, das sind vielleicht 4 Stunden, keine Ahnung. Das heißt der Stoff wird in weniger als 80 Stunden vermittelt und mit Klassenarbeiten, Übungsaufgaben geprüft. Erstmal sind die Klassenarbeiten ein Zeitfresser, andererseits gibt es während des Unterrichts sicher auch langsame Schüler die öfter mal nachfragen, Nervensägen die den Unterricht stören... das verzögert alles.

.... echt, keine Ahnung was du für eine Erwartungshaltung hast. Ich glaube du bist einfach zu lang aus der Schule raus.

 

Um einen Punkt aber nochmal aufzugreifen.

Zitat

Die kann man vielleicht in der 7. Klasse verwenden, damit die Schüler ein bisschen Spaß haben können

Die kann man auch für Anfänger in der Programmierung verwenden, damit diese Anfänger ein bisschen Spaß haben können.

Vielleicht ist es ja mit sein Ziel das Interesse nach mehr zu wecken. Von der 7. Klasse zur Ausbildung ist es übrigens nicht so weit hin wie du vielleicht denkst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1
vor 7 Stunden schrieb PVoss:

Beachtest du auch welcher Umfang da überhaupt vermittelt werden soll, über welche (geringe) Dauer und von welchem Startpunkt aus? Soll man auch das Wort Aushilfslehrer mal fett hervorheben?

Ist doch ganz gleichgültig, ob es ein Aushilfslehrer ist, oder nicht. Er soll die Schüler vernünftig unterrichten. Auch handelt es sich hier nicht um eine 7. Klasse, wo es scheißegal ist, ob sie Objektorientierung verstehen oder nicht, sondern es geht um Azubis, dies dies in ihrem Berufsleben brauchen. Der Lehrer springt aber von den Klassen zu Arrays, ohne überhaupt mal zu erklären, wozu überhaupt Klassen gedacht sind. Er verschiebt den Code nur von einer Klasse zur nächsten ... Ja, wow. Dafür brauche ich kein C#, sondern kann dafür auch eine prozedurale Sprache, wie z.B. Pascal, nehmen. Es hat doch keinen Sinn, eine Objektorientierte Sprache zu wählen, wenn man den Azubis nicht mal erklärt, was Objektorientierung überhaupt ist. Er springt auch mit den Themen kreuz und quer ohne einen roten Faden zu besitzen. z.B. von den erwähnten Klassen zu Arrays oder von der for-Schleife zu Modulo und von Modulo zur Random-Klasse. Was ist mit den anderen Arten von Schleifen? Von WinForms zu Boolesche Algebra. Was ist das denn für ein Unterricht? Man sieht ja, was dabei rauskommt, nämlich nichts ...

vor 7 Stunden schrieb PVoss:

Weiß du eigentlich, dass da auch die schlechteren Schüler mitgenommen werden sollen? Da kann man einfach nicht so schnell machen.

Wenn man aber bei den Themen von Pontius zu Pilatus springt, nimmt man die schwachen Schüler nicht mit. Im Gegenteil. Sie verlieren schneller den Überblick, weil sie den Themen einfach nicht folgen können. Im Unterricht sollte ein roter Faden zu sehen sein und der fehlt hier komplett. Es wird irgendwie alles nur kurz angerissen ohne näher darauf einzugehen. Sorry, aber mit so einem Wissensstand kann man noch keine Programme mit C# schreiben, da einfach das komplette Wissen über Objektorientierung fehlt. Wenn man schon die Objektorientierung weglassen möchte, was bei Anfängern vielleicht durchaus verständlich ist, dann sollte man auch meiner Meinung nicht mit einer OO-Sprache anfangen, weil es sonst für Verwirrung sorgt. Bei meiner Assistenten-Ausbildung wurde auch mit Pascal anfangen aber Pascal ist heute wohl nicht mehr "fancy" genug. Meine damalige Ausbildung habe ich 2008 begonnen und 2011 abgeschlossen. Das Problem sieht man schon in diesem Video von ihm. Er beschreibt den Konstruktor falsch. Er implementiert einen Konstruktor, nur weil er Quelltext sparen möchte. Das ist aber nicht der Sinn und Zweck eines Konstruktors. Der Konstruktor ist dafür da, um ein Objekt zu initialisieren. Parameter reicht man dann in ein Konstruktor rein, wenn das Objekt Daten von außerhalb benötigt. Zwar hat er genau das vor aber er erwähnt es nicht. Seine Intention ist nur, dass er zwei Zeilen Code weniger schreiben möchte. Dies ist einfach unbrauchbar und sorgt auch nicht für ein besseres Verständnis, sondern für mehr Verwirrung.

Je mehr ich mir die Unterlagen anschaue, desto mehr wird mir auch die Probleme von @Tician klar. Der Lehrer versucht zwar die Basics einer imperativen Programmiersprache zu zeigen, versucht aber gleichzeitig prozedural in einer reinen objektorientierten Sprache zu entwickeln. Das kann einfach nicht klappen, ohne dass es verwirrend wird. Da kommen wir wieder zu dem Problem, was ich oben erwähnte. Wenn man einfach nicht die Zeit hat, die Objektorientierung zu erklären, dann sollte man auch nicht mit einer objektorientierten Sprache anfangen, sondern mit einer rein prozeduralen Sprache.

Auch das wichtigste Werkzeug eines Entwicklers, wird nicht mal besprochen: Der Debugger. Ohne den Debugger könnte kein Entwickler überleben aber nirgends wird mal der Debugger erwähnt und das Problem sieht man hier doch auch: Der TE ist nicht in der Lage, seinen eigenen Code zu debuggen. Taucht ein Fehler auf, ist der TE sofort aufgeschmissen. 

vor 7 Stunden schrieb PVoss:

Die kann man auch für Anfänger in der Programmierung verwenden, damit diese Anfänger ein bisschen Spaß haben können.

Vielleicht ist es ja mit sein Ziel das Interesse nach mehr zu wecken. Von der 7. Klasse zur Ausbildung ist es übrigens nicht so weit hin wie du vielleicht denkst.

Mag sein, aber das Problem sieht man doch hier überdeutlich: Der TE hat zwar Interesse nach mehr und möchte in der Firma ein eigenes Programm schreiben aber eckt überall an, weil er/sie überhaupt kein Verständnis für die Objektorientierung oder für C# besitzt. Man kann nicht einfach eine rein objektorientierte Sprache nehmen und die Objektorientierung weglassen. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
public List<string>[,] GetList()
        {
            return liste;
        }

mit entsprechendem Aufruf

                List<string>[,] liste = datei.GetList();

Doch etwas gefunden das ich verstehe^^ Schauen wir mal ob es später funktioniert :)

Thema kann offen bleiben ich bin mir sicher das ich noch ein paar mal gegen die Wand rennen werde sobald ich das Programm mal starte.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Anbei meine Gedanken zu deinem Code, nicht völlig sortiert:

Ich würde an deiner Stelle mit dem if einfach abfragen ob sourceArray > 0 ist, und die for schleife dann in den Block packen.

Wenn du das sr.Close() aus der for schleife entfernst, und dann hinter den catch{}-Block ein finally{}-Block hängst, wird der in jedem Fall geschlossen.

Du solltest die Attribute noch Kapseln, also private String sourcePath etc. Visual Studio bietet dir dann, unter Strg+ oder rechte Maustaste auf die Deklaration des Attributs, automatisch an die Getter/Setter zu erstellen.

Ich würde das Durchsuchen der Dateien vermutlich in eine eigene Methode auslagern, und nicht im Konstruktor durchführen.

Die for Schleife kann vermutlich durch eine foreach-Schleife ersetzt werden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ich weiß jetzt nicht genau, wie ichs erklären soll, das muss man sich halt irgendwie über die Praxis aneignen... Ich versuchs aber mal:

"DateiEinlesen" hört sich für mich weniger wie eine Klasse an, sondern eher nach einer Methode. Klassen sind eher Substantive, Methoden eher Verben. "File", "FileHelper", "Auto", "Kunde", "Console" = Klassen, "readFile", "addCustomer", "moveTo", "writeLine" usw. = Methoden.

Vielleicht hilft dir das ein bisschen, das OOP ein wenig besser zu verstehen. Auf deinen Code angewendet wäre das dann "File" die Klasse mit der Methode "dateiEinleisen".

vor 19 Stunden schrieb Tician:

1. Problem: Ich weiß wie ich über den Konstruktor Variablen von meiner Main-Klasse in die andere Klasse zum benutzen weitergeben kann. Ich hab absolut null Ahnung oder Erfahrung wie ich meine 2-dimensionale Liste zurück an meine Main-Klasse geben kann um sie dort für weitere Zwecke zu benutzen (später an eine weitere Klasse zu übergeben).

Wodurch sich dieses Problem löst: Ein Konstruktor hat keinen Rückgabewert. Eine Methode "dateiEinlesen" dagegen schon.

vor 19 Stunden schrieb Tician:

2. Problem: der StreamReader sollte (wenn ich das richtig verstanden habe) auch bei einer Exception ein Close() bekommen, das ist mir aber hier nicht so möglich wie ich es wollte. Wie machen andere das?

Du deklarierst die Variable "sr" nicht im Try-Scope (Bezugsrahmen { ... }), sondern davor. close() kannst du dann im Finally aufrufen, was sicherstellt, dass deine Ressource auf jeden Fall geschlossen wird, egal ob eine Exception geworfen wird oder nicht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

@Whiz-zarD Du hast dir so viel Mühe gegeben und ich hab mir das jetzt 4 mal durchgelesen, das ist so mega viel das ich gar nichts mehr verstehe (du wolltest es wahrscheinlich gleich perfekt haben?), wenn ich das übernehme hätte ich auch ein Programm in C oder sowas abschreiben können. Es ist nicht mehr meines, ich verstehe gar nicht was da vorgeht und ohne tausend Kommentare geht da nix.

War mein eigenes Vorgehen denn so falsch? Ich hatte vor das beizubehalten, aber aus der Klasse vielleicht ein "CsvDatei" zu machen mit evtl Methoden "Einlesen", "Aufspalten" irgendwie sowas... mich verlässt gerade ziemlich schnell die Motivation und der Mut :(

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Mein Beispiel ist bei weitem nicht perfekt. Ich wollte dich auch nicht entmutigen, sondern einfach zeigen, dass auch erfahrene Entwickler erstmal anfangen und dann den Code stückweise verbessern. Niemand schreibt auf Anhieb guten Code. Man muss aber Erfahrungen sammeln, um ein Gefühl für die Sprache zu bekommen. Mit Erfahrungen merkt man auch, wenn etwas vielleicht nicht ganz so elegant ist und man vielleicht noch mal drüber nachdenken sollte. 

Ich wollte nur aufzeigen, wie ich an solche Dinge rangehe. Du solltest einfach Mut besitzen, mal etwas auszuprobieren. Kaputtmachen kannst du ja nichts. ;) Wenn du sogar eine quellcodeverwaltung, wie z.B. Git, nutzt, dann kannst du sogar ganze Änderungen wieder rückgängig machen. 

Du kannst auch Fragen stellen und mit anderen Leuten über dein Code reden. Ich denke, niemand reißt dir deswegen den Kopf ab. Das einzige, was ich erwarte, ist, dass man auch die Ratschläge von anderen annimmt und sie mal ausprobiert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ich nehme den Ratschlag an das ich erstmal Methoden mache statt alles in den Kontruktor zu kloppen, wenn ich dann den Austausch von Daten zwischen Klassen, Methoden und weißnichtwas hin kriege bin ich schon glücklich...

Der Rest muss folgen wenn das Programm auf diese Weise wieder fehlerfrei funktioniert, dann würde ich mich trauen noch einmal umzubauen. Ich brauch einen Zwischenschritt.

Edit: Es fängt schon an mit dem Problem das ich gar nicht weiß nach was ich meine CSV benennen kann, anders als bei einer Datenbank habe ich nichts das eine Zeile eindeutig identifiziert, es gibt keine durchnummerierung oder sowas, ich hab Zeilen doppelt oder dreifach

Bearbeitet von Tician
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
vor 2 Stunden schrieb Tician:

Edit: Es fängt schon an mit dem Problem das ich gar nicht weiß nach was ich meine CSV benennen kann, anders als bei einer Datenbank habe ich nichts das eine Zeile eindeutig identifiziert, es gibt keine durchnummerierung oder sowas, ich hab Zeilen doppelt oder dreifach

Eine CSV-Datei ist ja auch nichts weiteres, als eine Tabelle. Was für Daten stecken denn in der Datei? Ob die Daten doppelt und dreifach sind, ist ja auch erstmal egal. Ein Problem nach dem anderen. ;)

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Muss ich wohl wieder etwas Tiefer in die Tasche greifen.

Ich weiß auch nicht was alle Begriffe der ersten Zeile Bedeuten, die die ich aus den Abkürzungen auslesen kann sind:

Datum, Packstück-Nummer, Auftrags-Nummer, Paketnummer, Bezeichnung, Menge, Lagerplatz

Wie nenne ich das?

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ich nehme mal an, dass das aus der Logistik kommt. Ich kenne mich da mit den Begrifflichkeiten nicht aus. Ich nehme aber mal an, dass Daten aus deiner Firma sind. Die Daten stammen ja mit Sicherheit auch aus einer Datenbank, also muss das Kind bei euch ja einen Namen haben. Frage doch deinen Ausbilder. Spontan und ohne den Kontext zu kennen, würde ich aber behaupten, dass es sich hierbei um eine Kanban-Karte für einen Logistiker handelt, der mit diesen Informationen die Pakete packt.

Unabhängig von dem Klassennamen kannst du aber dennoch schon den Inhalt der Klasse füllen:

public class Xyz
{
    public virtual DateTime Datum { get; set; }
    public virtual int PackstueckNummer { get; set; }
    public virtual int Auftragsnummer { get; set; }
    public virtual int Paketnummer { get; set; }
    public virtual string Bezeichnung { get; set; }
    public virtual int Menge { get; set; }
    public virtual string Lagerplatz { get; set; }
}

Für Xyz muss dann noch ein passender Name gefunden werden. Bei PackstueckNummer, Auftragsnummer, Paketnummer und Lagerplatz musst du dann mal schauen, ob die Datentypen richtig sind. Ich kenne die Daten nicht. Kann auch sein, dass Buchstaben erlaubt sind, dann müssen es Strings sein.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ja ich arbeite in einem Logistik/e-commerce Betrieb. Was ist dieses virtual in deinem Code? Das Problem ist das ich mir da zu viel Mühe machen würde alles was mich an der ganzen Datei interessiert ist nur "die 5. Nummer jeder Zeile", der Rest bleibt wie er ist.

Bearbeitet von Tician
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Das virtual könnte man auch weglassen. Ich schreibe es nur aus Gewohnheit hin, weil das NHibernate-Framework dies so möchte. Außerdem bietet es mir beim Testen gewisse Vorteile.

virtual bedeutet, dass diese Eigenschaft mittels Vererbung überschreibbar ist. Für gewöhnlich sind Eigenschaften und Methoden in C# nicht überschreibbar. Wenn man in einer vererbten Klasse eine Eigenschaft oder Methode aber überschreiben möchte, so muss sie in der Basis-Klasse als virtual definiert werden. Beispiel:

    public class A
    {
        public virtual string Hallo
        {
            get { return "Hallo"; }
        }
    }

    public class B : A
    {
        public override string Hallo
        {
            get { return base.Hallo + " Welt"; }
        }
    }

Die Eigenschaft Hallo in Klasse A liefert "Hallo" zurück, während die Klasse B "Hallo Welt" zurückliefert. 
Die Klasse B überschreibt die Eigenschaft von Klasse A und ruft mit base.Hallo erst mal die Eigenschaft in Klasse A auf und modifiziert diesen Wert.

 

vor einer Stunde schrieb Tician:

Das Problem ist das ich mir da zu viel Mühe machen würde alles was mich an der ganzen Datei interessiert ist nur "die 5. Nummer jeder Zeile", der Rest bleibt wie er ist.

Was ist denn die "5. Nummer jeder Zeile"? Welche Spaltenüberschrift besitzt dann diese Zeile?

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ich verstehe deine Nummerierung nicht.
Zuerst gibst du an, dass die CSV-Datei so aufgebaut ist:

Datum, Packstück-Nummer, Auftrags-Nummer, Paketnummer, Bezeichnung, Menge, Lagerplatz

Dann sagst du, dass du die siebte Nummer braucht und das wäre nach meiner Zählung "Lagerplatz".
Wo kommt denn deine "7. Nummer her"? Von was?

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Das war doch nur ein Beispiel was in der Datei drin steht (und ich entziffern kann), da stehen Abkürzungen in dem Header mit denen ich nichts anfangen kann. Lass mich erstmal meine erste Klasse fertig machen und herumprobieren wie ich Variablen rumschieben kann, ich wäre ja schon froh das zu verstehen, du weißt gar nichts wie frustrierend das ist wenn man sich vornimmt das kleine 1x1 zu lernen und jemand anderes aber gleich in einen Rechenbereich mit 20 nullen hinter der Zahl vordringen möchte.

Ich kann das Programm nicht mehr sehen und wenn das irgendwie mit Hilfe von Klassen und Methoden tut bin ich doch schon glücklich und kann es mit dem nächsten Programm gleich so anfangen - und dann wieder einen Schritt weiter gehen mit der Verbesserung.

Und ich möchte nicht noch mehr Preis geben und mir dadurch ärger einhandeln...

Bearbeitet von Tician
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
vor 3 Minuten schrieb Tician:

Das war doch nur ein Beispiel was in der Datei drin steht (und ich entziffern kann), da stehen Abkürzungen in dem Header mit denen ich nichts anfangen kann. Lass mich erstmal meine erste Klasse fertig machen und herumprobieren wie ich Variablen rumschieben kann, ich wäre ja schon froh das zu verstehen, du weißt gar nichts wie frustrierend das ist wenn man sich vornimmt das kleine 1x1 zu lernen und jemand anderes aber gleich in einen Rechenbereich mit 20 nullen hinter der Zahl vordringen möchte.

Sorry, aber ich kann nichts dafür, wenn du mit dem großen 1x1 anfangen willst, auch wenn du das kleine nicht kannst.
Dann muss ich sagen, dann ist das Projekt noch zu groß für dich. Dann fange mit kleineren Dingen an. Bei deinem Projekt brauchst du schon etwas mehr Übung und Erfahrung, um es wirklich auf die Beine stemmen zu können. Du hast vor, mehrere komplexe Themen zu bearbeiten und du verstehst nicht mal, wie man das erste Thema löst. 

Dann kaufe ein Buch für Anfänger und arbeite es durch. So wird das einfach nichts.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
vor 8 Minuten schrieb Whiz-zarD:

Dann kaufe ein Buch für Anfänger und arbeite es durch. So wird das einfach nichts.

Das sehe ich nicht so. Ein Buch beantwortet dir keine Fragen.

Sorry, aber leider kann ich nicht nachvollziehen, wie du aus dem Auslesen einer CSV-Datei einen solchen Elefanten machst.

Gerade am Anfang der Programmierung ist es normal, dass man keinen 100% Clean Code schreibt und alle möglichen Softwarepatterns versteht und anwendet.

Meine ersten Programme in Delphi, wenn ich daran denke, schaudert es mir. Aber ich habe es auf die Beine gestellt bekommen. Auch wenn ich von OOP noch nie gehört habe und die Logik in die Forms geklatscht habe.

Wenn man aber das Interesse und die Leidenschaft mitbringt, werden aus diesen anfänglich hässlichen Programmen, immer bessere. Vielleicht fängt man dann an das MVC-Pattern anzuwenden oder beschäftigt sich mit Polymorphie und Kapselung. Du überflutest Tician hier mit Begriffen und Techniken, die einige erfahrene Programmierer in meiner Firma nicht mal zu hören bekommen haben. Sei doch nicht so streng mit jemanden der gerade am Anfang steht.

 

Bearbeitet von Gottlike
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Ich verstehe dich nicht.

Ich kann programmieren, ob es gut ist ist eine andere Frage.

Du sagst keiner macht am Anfang perfekten Code und ich soll es mit der OOP einfach versuchen - aber du scheinst perfekten Code zu erwarten. Jetzt versuche ich es, du willst das ich es unbedingt ganz genauso mache wie du es willst und es dir vorstellst und wenn ich sage "das ist mir zu schwer" weil du zwangzig verschiedene Dinge benutzt von denen ich noch nie in meinem Leben gehört habe, die ich noch nie gesehen habe dann scheinst du beleidigt zu sein (so kommt es rüber) und erzählst mir "lern programmieren".

Du hast so viel Wissen und du versuchst es weiter zu geben - allerdings alles auf einmal. Mein erster Versuch war da - und die Rückmeldung "nicht in den Konstruktor, mach stattdessen Methoden daraus" kam bei mir an. Also war mein nächstes Vorhaben meine Klasse zum Dateien einlesen in ein paar Methoden aufzuspalten...

Das Projekt läuft, mir ist absolut die Lust daran vergangen irgendwas zu optimieren oder umzustellen, die anfängliche Freude ist weg, stattdessen würde ich am liebsten einfach heulen. Ich lass das jetzt ruhen und versuch es mit dem nächsten Projekt besser zu machen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
vor 18 Stunden schrieb Tician:

Das Projekt läuft, mir ist absolut die Lust daran vergangen irgendwas zu optimieren oder umzustellen, die anfängliche Freude ist weg, stattdessen würde ich am liebsten einfach heulen. Ich lass das jetzt ruhen und versuch es mit dem nächsten Projekt besser zu machen.

Ohne jetzt zynisch werden zu wollen: Das geht mir fast jede Woche so :D 

Nein Spaß, mal ernsthaft zu deinem Problem. Ich kann mich noch genau an meine Ausbildung erinnern, als ich vor vermeintlich einfachen Dingen saß, (auch hier im Forum) um Rat gebeten habe und dann mit mir völlig unverständlichen Lösungsvorschlägen zurecht kommen musste. Ich musste auch etwas schmunzeln, als ich Whiz-zarDs Beitrag gelesen hab (der nebenbei bemerkt sehr gut ist). Mein Verständnis für C# hält sich sehr in Grenzen, aber ich konnte alle Schritte gut nachvollziehen. Schmunzeln musste ich deshalb, weil ich gemerkt hab, dass es ihm selbst viel Spaß gemacht hat, fortgeschrittene Programmierkonzepte anhand eines recht überschaubaren Beispiels zu erklären. Du stehst nun da, wolltest eigentlich ein Kartenhaus bauen, fragst, wie man das am besten tut, ob das so ok ist und da kommt ein routinierter Architekt, der dir Statik & thermische Isolierung erklärt und Hinweise für die Integration von Wintergarten und Solaranlage in dein Haus gibt. Allerdings hat er auch erklärt, dass es sein Ansatz wäre und dass man natürlich nicht völlig übertreiben und mit Kanonen auf Spatzen schießen muss.
Dazu kommt ja, das ist allerdings meine persönliche Meinung, dass C# unglaublich kompliziert und verwirrend sein kann. Ich arbeite mit Ruby (on Rails) und wenn ich mir vorstelle, wie ich eine CSV einlesen und den Kram anzeigen lassen oder speichern würde, sähe das wesentlich simpler aus solange nichts dynamisch funktionieren muss...

Um es kurz zu machen: Du hast jetzt von verschiedenen tollen Sachen gehört, die man machen kann. Mehr solltest gar nicht. Fühl dich nicht aufgefordert, alles bis ins kleinste Detail verstehen zu müssen. Das baut Druck auf, das macht simple Dinge unnötig kompliziert und dann macht es auch keinen Bock mehr. Du wirst solche Momente noch öfter haben. Mach dich damit nicht verrückt, denn das war niemands Absicht. Viel Erfolg bei deinem nächsten Projekt!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Diese Frage beantworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

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...