Alle Beiträge von Whiz-zarD
-
Eigene Klasse in VB.net umschreiben für C#
Allerdings würde ich das so nicht machen, denn das würde wieder gegen das Single-Responsibility-Prinzip verstoßen, weil die Addition-Klasse wieder für zwei Dinge zuständig ist. Die Ausgabe sollte auch in der Nähe der View angesiedelt sein und nicht in der Geschäftslogik. Angenommen, man will die Addition unterschiedlich darstellen. Dann müsste man ja mehrere Methoden in ICalculation und ehe man sich versieht, besitzt das Interface plötzlich 50 Methoden. Wenn man eine hübsche Ausgabe will, dann könnte man auch die benötigten Informationen zur Verfügung stellen und eine weitere Klasse bastelt aus den Informationen einen String.
-
Eigene Klasse in VB.net umschreiben für C#
Das stimmt nicht ganz. Stellt man den Taschenrechner auf "Wissenschaftlich", so kennt er auch eine Operatorreihenfolge.
-
Eigene Klasse in VB.net umschreiben für C#
Ich glaube, es wird echt mal Zeit, dass ich mein Artikel "Wie man einen Taschenrechner programmiert" veröffentliche. Du meinst wohl die (umgekehrte) polnische Notation. Genannt auch Postfix- und Präfix-Schreibweise. Eine Umwandlung von der bekannten Infix-Schreibweise in die Post-/Präfix-Schreibweise, lässt sich durch den Shunting-Yard-Algorithmus lösen. Das würde hier aber viel zu weit gehen.
-
Eigene Klasse in VB.net umschreiben für C#
Im Grunde haben wir schon alles, was wir brauchen. Wir haben doch das Interface ICalculation, dessen Methode Calculate() ein double zurückgibt, also ein Parameter für die Addition-Klasse. Wenn du drei Zahlen miteinander addieren möchtest, kannst du es ganz einfach machen: new Addition(new Addition(1,2).Calculate(), 3) Jetzt rechnet er 1 + 2 + 3.
-
Eigene Klasse in VB.net umschreiben für C#
File.AppendAllText() macht im Grunde nichts anderes, was du geschrieben hast: public static void AppendAllText(String path, String contents) { // ... InternalAppendAllText(path, contents, StreamWriter.UTF8NoBOM); } private static void InternalAppendAllText(String path, String contents, Encoding encoding) { // ... using (StreamWriter sw = new StreamWriter(path, true, encoding)) sw.Write(contents); } So sieht der Source Code im .NET Framework aus.
-
Eigene Klasse in VB.net umschreiben für C#
Genau
-
Eigene Klasse in VB.net umschreiben für C#
Es geht um das DRY-Prinzip (Don't Repeat yourself). Wenn du nicht nur die Addition implementieren willst, sondern auch noch weitere Rechenoperationen, dann brauchen sie ebenfalls left und right. Damit man beide Variablen nicht für jede Operation kopieren muss, habe ich sie in eine abstrakte Klasse ausgelagert und jede Operation erbt von dieser Klasse. So braucht man die beiden Variablen nur ein mal definieren. Abstrakte Klassen sind nicht instanziierbar. Du kannst also kein new BinaryCalculation() aufrufen. Das führt sofort zu ein Kompilierfehler. Abstrakte Klassen dienen für eine Basisimplementierung einer Funktionalität. Klassen, die dann von der abstrakten Klasse erben, implementieren dann die konkrete Fachlogik. Die Subtraction-Klasse wird dann einfach so aussehen: Public Class Subtraction Inherits BinaryCalculation Public Sub New(left As Double, right As Double) MyBase.New(left, right) End Sub Public Overrides Function Calculate() As Double Return Me.left - Me.right End Function End Class left und right braucht man ja nicht noch mal definieren, weil sie eben schon in BinaryCalculation definiert worden sind.
-
Eigene Klasse in VB.net umschreiben für C#
Viele Wege führen nach Rom. Allerdings ist das Problem von WinForms-Anwendungen, dass sie den Entwickler nicht an "die Hand nehmen". Eine Form sollte eigentlich nur die Logik besitzen, die auch für die Anzeige notwendig ist. Siehe das MVC (Model-View-Controller) bzw. MVP (Model-View-Presenter) oder für WPF-Anwendungen das MVVM (Model-Viel-ViewModel)-Pattern. Da es aber so schön einfach ist, ein Button in die Form per Drag'n'Drop in die Form zu schieben und dann mit einem Doppelklick das Event zu implementieren, sind diese Patterns nicht so ganz ersichtlich. Bei den Patterns wird die grafische Oberfläche von der Geschäftslogik getrennt. Der Grund ist einfach der, wenn man die Geschäftslogik von der grafischen Oberfläche trennt, kann man die grafische Oberfläche recht leicht austauschen. Angenommen du entwickelst eine WinForms-Anwendung und willst sie später in eine Web-Applikation überführen. Wenn die Geschäftslogik aber nun in der grafischen Oberfläche steckt, müsstest du die gesamte Anwendung neu schreiben. Lagert man sie hingegen in eine separate Klasse aus, so braucht man letztendlich im Idealfall nur die grafische Oberfläche austauschen. Man lagert also die Geschäftslogik in eine separate Klasse (der Controller) aus und die grafische Oberfläche (die View) kommuniziert über eine Schnittstelle mit der Geschäftslogik. Ein weiterer Grund für das Auslagern der Geschäftslogik ist wieder die Testbarkeit. Wenn du das Logging automatisch per Unittest testen möchtest, musst du wiederrum die Form-Klasse erzeugen und ein Klick auf den Button simulieren. Da die Events private sind, kannst du die Events nicht von Außen aufrufen. Dann muss man wieder andere Tools verwenden, die eine Anwendung automatisch starten und testen kann oder man muss mittels Reflection das Event ausführen aber das alles verkompliziert den Test und sollte vermieden werden und ist auch sehr fehleranfällig. Liegt das Logging aber in einer separaten Klasse, die von außen steuerbar ist, ist der Unittest mit drei Zeilen Code erledigt. Die LoggableCalculation-Klasse ist im Grunde auch nur ein Kompromiss, weil die Calculate()-Funktion nicht nur das Ergebnis berechnet und zurückgibt, sondern auch das Ergebnis loggt und somit auch gegen das Single-Responsibility-Prinzip verstößt aber es ist in dem Sinne ein Kompromiss, weil die Berechnung in einer separaten Klasse liegt und die LoggableCalculation-Klasse erweitert die Berechnung ums Logging. Dieses Vorgehen nennt sich auch Decorator-Pattern. Wenn du in deinem Beispiel das Ergebnis der Addition in eine Textdatei speichern möchtest, müsstest du im Grunde nur folgende Zeile Dim Addi As New Addition(2, 5) gegen Dim logger As New FileLogTraceListener With { .CustomLocation = "D:\", .BaseFileName = "test" } Dim LoggableCalculation As New LoggableCalculation(New Addition(2, 5), logger) austauschen. Visual Basic besitzt schon mehrere integrierte Logger. Der FileLogTraceListener ist ein Logger, der in eine Datei schreibt. Einen Standard-Logger könnte man über die app.config-Datei konfigurieren und per My.Application.Log aufrufen aber ich erzeuge hier mal eine eigene Instanz von einem Logger, weil es sonst zu weit führen würde. Die LoggableCalculation-Klasse sieht dann wie folgt aus: Public Class LoggableCalculation Inherits ICalculation Private ReadOnly calculation As ICalculation Private ReadOnly logger As TraceListener Public Sub New(calculation As ICalculation, logger As TraceListener) Me.calculation = calculation Me.logger = logger End Sub Public Overrides Function Calculate() As Double Dim result As Double result = Me.calculation.Calculate() Me.Log(result) Return result End Function Private Sub Log(result As Double) logger.WriteLine(result) End Sub End Class Wenn du dann die Calculate()-Funktion aufrufst, wird dann unter D:\ die Datei test.log erzeugt. Den Pfad und den Dateinamen kannst du im oberen Code anpassen. Wie du dann siehst, ist das Erzeugen der Log-Datei komplett unabhängig von der Form und ich könnte den Code somit auch z.B. in einer Konsolen-Anwendung verwenden: Sub Main() Dim logger As New FileLogTraceListener With { .CustomLocation = "D:\", .BaseFileName = "test" } Dim LoggableCalculation As New LoggableCalculation(New Addition(5, 3), logger) Console.WriteLine(LoggableCalculation.Calculate()) Console.ReadKey() End Sub Oder als Test (hier als Beispiel mit dem Unittest Framework von Microsoft): <TestClass()> Public Class UnitTest1 <TestMethod()> Public Sub Five_Plus_Two() Dim calculation As New Addition(5, 2) Assert.AreEqual(7.0, calculation.Calculate()) End Sub <TestMethod()> Public Sub Log_Five_Plus_Two() Dim calculation As New Addition(5, 2) Using logger As TraceListener = CreateTraceListener() Dim LoggableCalculation As New LoggableCalculation(calculation, logger) LoggableCalculation.Calculate() End Using Assert.AreEqual(True, File.Exists("D:\test.log")) Assert.AreEqual($"7{Environment.NewLine}", File.ReadAllText("D:\test.log")) End Sub Private Function CreateTraceListener() As TraceListener Return New FileLogTraceListener With { .CustomLocation = "D:\", .BaseFileName = "test", .Append = False } End Function End Class Ich kann hier also die gesamte Funktionalität testen, ohne dabei die Anwendung starten und auf den Button drücken zu müssen. Die Prozedur Five_Plus_Two() überprüft, ob das Ergebnis von 5 + 2 = 7 ist und Log_Five_Plus_Two() überprüft, ob eine Log-Datei geschrieben wurde und ob dort 7 drinnensteht. Unter Visual Studio sieht es dann so aus: So kann man auf Knopfdruck etliche Tests durchführen, ohne einmal die Anwendung gestartet zu haben. Das erleichtert das Leben erheblich, weil man so schnell Feedback bekommt, ob die Geschäftslogik funktioniert. Man muss sich dann nicht mühselig durch alle Buttons und Menüs klicken. Ob der Button allerdings das tut, was er auch soll, muss dann aber per manuellen Test herausgefunden werden aber ich habe die darunterliegende Funktionalität per Unittest getestet.
-
Eigene Klasse in VB.net umschreiben für C#
ICalculation ist keine Klasse, sondern ein Interface. Ein Interface definiert die Schnittstelle nach außen. Es ist quasi eine leere Hülle und gibt die Funktionen vor, die eine Klasse implementiert haben müssen. Deswegen ist es in meinem Beispiel dem Logger egal, was für eine Berechnung dahintersteckt, da alle Berechnungen das Interface implementieren und somit alle eben die Funktion Calculate() haben. Der Logger war von mir nur frei erwunden. Es gibt den in dieser Form nicht. Er war von mir nur ein abstraktes Beispiel, um die Prinzipien zu verdeutlichen und was passiert, wenn man weitere Features hinzufügen möchte. Wenn du etwas loggen willst, kannst du natürlich einen eigenen Logger schreiben. In Visual Basic bin ich aber leider nicht so firm drinnen, da ich mit C# arbeite aber ich denke mal, für Visual Basic gibt es auch schon fertige OpenSource-Logger, die man verwenden kann. Für C# gibt es z.B. NLog und NLog bietet von Haus aus über 30 verschiedene Möglichkeiten, etwas zu loggen (z.B. auf die Konsole, als Textdatei, als E-Mail, in eine Datenbank, in Slack, ...) und wenn das nicht reicht, der kann weitere hinzuprogrammieren.
-
MSSQL Datenbank-Abfrage Datensatz für jedes Datum aus Datumsbereich
Wie gesagt, ich kenne mich mit MS SQL nicht aus, da ich hauptsächlich mit Oracle Database zu tun habe. Dort gibt es die sog. Table Functions. Also eine Funktion, in der du Parameter reinreichen kannst und dir eine Tabelle zurückliefert. Unter MS SQL scheint sowas unter dem Begriff "Table-Valued Functions" zu geben. https://www.codeproject.com/Articles/167399/Using-Table-Valued-Functions-in-SQL-Server
-
MSSQL Datenbank-Abfrage Datensatz für jedes Datum aus Datumsbereich
Ich vermute mal, dass jeder Tag zwischen den beiden Daten ausgewiesen werden soll. Also: ID Datum Von Bis 1 01.01.2000 01.01.2000 10.01.2000 1 02.01.2000 01.01.2000 10.01.2000 1 03.01.2000 01.01.2000 10.01.2000 1 04.01.2000 01.01.2000 10.01.2000 1 05.01.2000 01.01.2000 10.01.2000 1 06.01.2000 01.01.2000 10.01.2000 1 07.01.2000 01.01.2000 10.01.2000 1 08.01.2000 01.01.2000 10.01.2000 1 09.01.2000 01.01.2000 10.01.2000 1 10.01.2000 01.01.2000 10.01.2000 Sowas ist mit reinem SQL nicht möglich, da SQL auf der Menge arbeitet, die in der Datenbank stehen. Du willst hier aber neue Zeilen dazudichten. Sowas würde höchstens mit einer Stored Procedure gehen. Ich kenne mich aber mit MS SQL nicht wirklich gut aus und weiß auch nicht, was man dort für Stored Procedure bauen könnte. Mit Oracles PL/SQL wäre es möglich.
-
Eigene Klasse in VB.net umschreiben für C#
Genau, die Methode macht einfach zu viel. Außerdem ist es sie schwieriger zu testen, da die Funktion nun eine sog. zyklomatische Komplexität von 5 hat. Das bedeutet, dass deine Funktion fünf Pfade hat, die durchlaufen werden können. Wenn du jetzt Unittests schreiben würdest, müsstest du mindestens 5 Tests schreiben, nur um diese eine Funktion zu testen. Du merkst auch vielleicht selber, dass du mit Return 0 ein Hilfskonstrukt bauen musstest, damit die Funktion funktionieren kann. Also zusätzliche Komplexität, die beim Lesen nur stört. Desweiteren verstößt diese Art von Porgrammierung gegen das sog. OpenClosed-Prinzip, da wir bei weiterer Funktionalität die Funktion modifizieren müssen. Angenommen, wir wollen auch noch Modulo-Operator implementieren. Dafür müssen wir dann die Funktion modifizieren. In meiner Variante muss nur eine neue Klasse angelegt werden. Das verhindert, dass der Entwickler, bei der Modifikation, Fehler einbaut, sodass andere Operationen plötzlich nicht mehr funktionieren. Da wir den Code nämlich nicht modifizieren, funktioniert alles so wie gehabt. Darüberhinaus ist der Funktionsaufruf nun auch noch schwerer zu lesen. Du verstehst vielleicht noch, was die 1 bedeutet aber jemand anderes weiß es nicht und ist entweder auf deine Dokumentation oder auf den Code angewiesen, um nachzuschauen. Sicherlich, die 1 könnte man auch noch gegen ein Enum austauschen, um es sprechender zu machen aber nicht desto trotz hast du die o.g. Probleme. Du musst nämlich eines bedenken: Ein Entwickler liest 80% seiner Tageszeit Code und in den restlichen 20% schreibt er Code und da sollte der Code so verständlich und einfach wie möglich sein. Das ist zwar schon alles auf einen höheren Niveau, was ich hier erzähle aber ich weiß noch, wie ich angefangen habe, zu entwickeln und für mich wären diese Informationen damals echt Goldwert gewesen. Wenn du es am Anfang nicht verstehst, ist es auch in Ordnung. Softwareentwicklung ist nun mal eine Gratwanderung und in jeder Situation muss man neu abschätzen, welcher Weg am sinnvollsten ist. Es kommt sogar sehr häufig vor, dass man sich verzettelt und sein Plan über den Haufen schmeißen muss, weil eine Situation kommt, an die man nicht gedacht hat. btw. die ganzen Prinzipien, die ich genannt habe, sind unter dem Begriff SOLID-Prinzipien zusammengefasst. SOLID steht für: Single-Responsibility-Prinzip Open-Closed-Prinzip Liskovsches Substitutionsprinzip Interface-Segregation-Prinzip Dependency-Inversion-Prinzip
-
Eigene Klasse in VB.net umschreiben für C#
Kann man machen, würde ich aber nicht tun. Methoden, die statische Methoden aufrufen, sind schwerer zu testen, weil man die statische Methode mittestet. Besonders wenn die statische Methode Fehler verursachen kann, wird es sehr problematisch, da die Lokalisierung des Fehlers aufwendiger wird, da der Fehler ggf. in der statischen Methode aufgetreten ist. Beispiel: Man möchte, dass die Berechne()-Funktion nicht nur das Ergebnis zurückliefern soll, sondern das Ergebnis soll in eine Log-Datei geschrieben werden und beim Schreiben in die Log-Datei könnten Probleme auftreten. Außerdem würde so eine Klasse gegen das Single-Responsibility-Prinzip verstoßen, weil sie zwei Dinge macht: Zwei Zahlen addieren Ergebnis loggen Ich persönlich meide statische Funktionen/Methoden so weit, wie es geht. So umgeht man viele Probleme. Ich hab angefangen Klassen so zu schreiben, sodass sie von Außen kaum gesteuert werden. Die Additionsklasse hätte ich wie folgt geschrieben: Public Class Addition private ReadOnly left As Double private ReadOnly right As Double Public Sub New (left As Double, right As Double) Me.left = left Me.right = right End sub Public Function Calculate() As Double Return Me.left + Me.Right End Function End Class Das hat jetzt den Vorteil, dass man die Calculate()-Funktion in ein separates Interface ablegen kann, was jede erdenkliche Art von Berechnungen implementieren könnte, wenn wir weiterdenken, als die vier Grundrechenarten. z.B. Quadratwurzel, Sinus, Cosinus, Tangens, etc. Darüber hinaus könnte man noch die Variablen left und right in eine abstrakte Klasse abstrahieren, weil sie auch für die anderen drei Grundrechenarten benötigt werden und wir somit das DRY-Prinzip einhalten. Das ganze Konstrukt könnte dann so aussehen: Public MustInherit Class ICalculation MustOverride Function Calculate() As Double End Class Public MustInherit Class BinaryCalculation Inherits ICalculation Protected ReadOnly left As Double Protected ReadOnly right As Double public Sub New (left As Double, right As Double) Me.left = left Me.right = right End Sub End Class Public Class Addition Inherits BinaryCalculation Public Sub New(left As Double, right As Double) MyBase.New(left, right) End Sub Public Overrides Function Calculate() As Double Return Me.left + Me.right End Function End Class Die Klassen für Subtraktion, Multiplikation und Division würden analog so aussehen, wie die Addition-Klasse. Eine Klasse für einen Logger könnte so aussehen: Public Class LoggableCalculation Inherits ICalculation Private ReadOnly calculation As ICalculation private ReadOnly logger As Logger Public Sub New(calculation As ICalculation, logger As Logger) Me.calculation = calculation Me.Logger = logger End Sub Public Overrides Function Calculate() As Double Dim result as Double result = Me.calculation.Calculate() Me.Log(result) Return result End Function private Sub Log(result As Double) If(Not Me.logger Is Nothing) logger.Log(result) End If End Sub End Class Es ist dem Logger nun egal, ob es eine Addition oder die Berechnung zur Weltherrschaft ist, solange calculation das ICalculation-Interface implementiert. Somit könnte man die Berechnungen und den Logger isoliert testen.
-
Eigene Klasse in VB.net
Du schmeißt hier Begriffe etwas durcheinander. "Vererben" bedeutet was anderes. Vererben ist, wenn eine Klasse von einer anderen Klasse erbt. Beispiel: Public Class BonusAddiere Inherits Addiere public Function BerechneBonus() As Integer Return MyBase.Berechne() * 2 End Function End Class Die Klasse BonusAddiere erbt von Addiere (achte auf das Schlüsselwort Inherits). Die Methode BerechneBonus() holt sich das Ergebnis von Berechne() aus der Basisklasse und multipliziert diesen Wert mit 2. Die Vererbung ist einer der Grundkonzepte der Objektorientierung, die du verstanden haben solltest, wenn du mit einer objektorientierten Sprache arbeiten möchtest. Die Zeile Dim add As New Addiere Erstellt nur ein Objekt der Klasse Addiere, und weist es der Variable add zu. In anderen Programmiersprachen (z.B. C#) würde es so aussehen: var add = new Addiere(); Da wird es vielleicht ein bisschen deutlicher, dass wir hier nur eine Variable mit dem namen add definieren, die als Wert ein Objekt von Addiere bekommt.
-
Eigene Klasse in VB.net
Deine Prozedur ShowErgebnis() ist schon mal nicht richtig. Es muss eine Funktion sein, die eben zahl1 und zahl2 addiert und das Ergebnis zurückgibt. Dann kannst du in der Prozedur Button3_Click() einfach das Ergebnis einer TextBox zuweisen. Public Class Addiere Public Property Zahl1 As Integer Public Property Zahl2 As Integer Function Berechne() As Integer Return Zahl1 + Zahl2 End Function End Class Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim add As New Addiere add.Zahl1 = 5 add.Zahl2 = 3 TextBox1.Text = add.Berechne() End Sub Deine Addieren-Klasse sollte nicht dafür zuständig sein, das Ergebnis in die Textbox zu schreiben. Sie sollte nur das Ergebnis zurückliefern und die Anzeige in der Textbox sollte die Klasse übernehmen, die es auch braucht. Ansonsten ist deine Addieren-Klasse abhängig von der TextBox und die Klassen sollten so unabhängig wie möglich sein.
-
Projektantrag: Entwicklung eines Telefon SoftClient mit Anbindung zu der Verwaltungssoftware xxx
So, wie ich das sehe, unterstützt MobyDick doch tel:// sip:// und callto:// URIs.
- Welche Programmiersprache lernen? C++?
-
Projektantrag: Importkonverter für Bestelldateien
Klingt ein nach einem ETL-Prozess.
- Welche Programmiersprache lernen? C++?
-
Welche Programmiersprache lernen? C++?
Wenn es um die Konzepte geht, dann solltest du das nehmen, was die Schule auch lehrt, denn C++ ist nicht Java. Auch wenn beide Sprachen objektorientiert sind (was bei C++ nur die halbe Wahrheit ist), haben dennoch auch objektorientierte Sprachen andere Konzepte. z.B. in C++ muss man mit Pointern rumhantieren, während in Java dies auf ein Minimum reduziert wurde und sich dort Referenzen nennen. Auch hat C++ keinen Garbage Collector. Du musst dich dort selbst um die Reservierung und Freigeben des Speichers kümmern, während in Java dies der Garbage Collector für dich dies übernimmt. C++ unterstützt außerdem das Konzept der Mehrfachvererbung und benötigt daraufhin keine Interfaces. Interfaces in C++ wären Klassen mit virtuellen Methoden. Apropos virtuelle Methoden: Die Überladung von Methoden funktioniert in C++ genau andersrum als in Java. Nur virtuelle Methoden können in C++ überschrieben werden, während in Java alle Methoden, außer die, die mit einem final markiert sind, überschrieben werden. Wenn ihr also was entwickeln sollt und du nimmst C++, während der Lehrer nur Java kennt und du nicht weiterkommst, dann siehst du halt sehr alt aus. C++ ist also nicht immer das Allheilmittel für alle Fälle und wenn es um das Erlernen der Konzepte der Objektorientierung geht, dann ist C++ auch nicht wirklich die beste Sprache, weil man sehr viel Boilerplate Code schreiben muss.
-
Wieso "var null = NULL;"
Macht für mich auf dem ersten Blick keinen Sinn. Wohl eher eine interne Geschichte, wie @Klotzkopp schon schreibt. PHP und JavaScript sind ja Sprachen, die gerade von Anfängern sehr beliebt ist und da werden gerne mal Sachen kopiert, ohne zu wissen, was das eigentlich soll. So ein Konstrukt ist höchstens auch nur bei dynamisch typisierten Sprachen möglich. In typisierten Sprachen, wie z.B. C# oder Java ist sowas nicht möglich.
-
Wieso "var null = NULL;"
Welche Sprache? Edit: So ein Konstrukt kenne ich nur, wenn man einen definierten Wert für "leer" haben möchte. Angenommen, du programmierst ein Schachspiel und ein leeres Feld auf dem Brett soll einen definierten Wert haben. Damit alle leeren Felder den selben definierten Wert haben, legt man so einen Wert fest da du aber weder die Sprache mitgeteilt hast, noch der Kontext, wo diese Variable verwendet wird, ist das nur reine Spekulation.
-
C# Zugriff auf externe Klassen
Das ist viel zu kompliziert und ich garantiere dir, spätestens nach zwei Wochen verstehst du deinen eigenen Code auch nicht mehr. Wieso gehst du dort nicht pragmatischer ran? Stell dir doch vor, eine Aufgabe wäre ebenfalls eine Klasse. Welche Informationen bräuchtest du denn, um eine Multiple-Choice-Aufgabe abzubilden? Aufgabentext Lösungsvorschläge Lösung Daraus könnte man ja eine Klasse bauen: public class Aufgabe { public string Aufgabentext { get; } public string[] Lösungsvorschläge { get; } public int[] Lösung { get; } public Aufgabe(string aufgabentext, string[] lösungsvorschläge, int[] lösung) { this.Aufgabentext = aufgabentext, this.Lösungsvorschläge = lösungsvorschläge, this.Lösung = lösung } } Damit könnte man ja nun eine Aufgabe definieren: Aufgabe aufgabe1 = new Aufgabe( "Wie viel ist 1+1?", new string[] {"4", "3", "2", "5"}, new int[] {2} ) In Lösungen stehen dann die Indizes der richtigen Lösungen aus Lösungsvorschläge. Wenn man jetzt weiter überlegen würde, gehören die Lösungsvorschläge und die Lösungen doch irgendwie zusammen und zwar gibt es einen Vorschlag und der ist entweder richtig oder falsch. Also könnte man daraus wieder eine Klasse bilden: public class Lösungsvorschlag { public string Text { get; } public bool IstRichtig { get; } public Lösungsvorschlag{string text, bool istRichtig { this.Text = text; this.IstRichtig = istRichtig; } } Also könnte man die Aufgabenklasse ändern: public class Aufgabe { public string Aufgabentext { get; } public Lösungsvorschlag[] Lösungsvorschläge { get; } public Aufgabe(string aufgabentext, Lösungsvorschlag[] lösungsvorschläge) { this.Aufgabentext = aufgabentext; this.Lösungsvorschläge = lösungsvorschläge; } } Der Aufruf sieht dann so aus: Aufgabe aufgabe1 = new Aufgabe( "Wie viel ist 1+1?", new Lösungsvorschlag[] { new Lösungsvorschlag("4", false), new Lösungsvorschlag("3", false), new Lösungsvorschlag("2", true), new Lösungsvorschlag("5", false) } ); Du hast hier dann eine Struktur, mit der es möglich ist, ohne Mathematikkünste herauszufinden, welche Antwort richtig und falsch ist. Wenn man das jetzt weiterspinnt, dann könnte man daraus auch eine Textdatei machen, die eingelesen wird und daraus die Aufgaben-Objekte erzeugt. Eine weitere Klasse könnte ja dann die Auswertung übernehmen. Sie würde dann die Aufgabe und die Lösungen vom Benutzer bekommen und miteinander vergleichen. Wenn man die Probleme in kleinere Probleme aufteilt, dann benötigt man später keine allzugroßen Algorithmen und auch keine große "Magic". Der Code wird dadurch auch lesbarer und verständlicher. So was wie public static (oder allgemein static) sollte man auch vermeiden. Das sollte schon einen sehr guten Grund haben, warum man sowas machen möchte und nicht einfach nur, weil man es nicht besser weiß. static hat nun mal das Problem, dass es sich um eine Eigenschaft der Klasse handelt und nicht des Objektes, was dann zu unvorhergesehenen Verhalten der Objekte führen kann, da statische Werte überall verändert werden können. Angenommen, du arbeitest in einem größeren Projekt mit 1.000 Klassen und das Verhalten eines oder mehrere Objekte ändern sich. Angenommen, du hast mehrere Maschinen, die Nägel in ein Stück Holz hämmern und für die Maschinen gibt es ein gemeinsames Magazin für die Nägel und jemand tauscht die Nägel irrtümlicherweise gegen Kaugummi aus und jetzt versucht jede Maschine Kaugummi in das Holz zu hämmern und die gesamte Produktion steht still. Es wäre dann sinnvoller, jede Maschine hätte ihr eigenes Magazin und es würde dann nur eine Maschine ausfallen. Darum würde ich dir auch dazu raten, mit einer Konsolenanwendung anzufangen, anstatt mit einer Anwendung mit einer grafischen Oberfläche, um überhaupt ein Gefühl für die Sprache zu bekommen. Auch wenn Schulen immer was anderes suggieren und dann irgendwas zurecht frickeln, braucht man bei grafischen Oberflächen schon ein Verständnis für die Sprache und wie solche Oberflächen funktionieren. Auch wenn es schön einfach ist, einfach ein Button in die Form zu schieben und dann per Doppelklick das Event zu implementieren, so ist dies auch schon ein sehr schlechter Weg, um eine Anwendung zu bauen.
-
Nebenberuflich entwickeln, was kann man verlangen?
Man sollte aber beachten, dass Nebeneinkünfte über 400 € versteuert werden müssen und deswegen machen meist solche Nebeneinkünfte wenig Sinn, denn hinterher hat man davon gar nichts. Daher sollte man es sic genau überlegen, ob man mehr als 400 € nehmen möchte.
-
C# Zugriff auf externe Klassen
Erstmal würde ich nicht für jede Aufgabe eine eigene Form bauen. Das widerspricht dem kompletten Gedanken der Objektorientierung. Ich würde also erst mal anfangen, zu überlegen, welche Arten von Aufgaben du hast (Multiple Choice, Rechenaufgabe, ...) und dafür geeignete Forms ausdenken. Eine Aufgabe kann ja selber eine Klasse sein. Deine "externe Klasse", die die Auswertung übernimmt kannst du ja per Dependecy Injection reinreichen. https://blogs.msdn.microsoft.com/dmx/2014/10/14/was-ist-eigentlich-dependency-injection-di/ Deine Forms besitzen dann eine Property, die als Typ deine "externe Klasse" entspricht. Bei der Instanziierung der Form reichst du dann deine "externe Klasse" rein. Beispiel: public class AnalysisClass { // ... } public class MyForm : Form { public MyAnalysisClass AnalysisClass { get; set; } /// ... } AnalysisClass analysisClass = new AnalysisClass(); MyForm myForm = new MyForm(); myform.AnalysisClass = analysisClass;