C# OOP Verständnis, GUI, Windows-Form, Probleme bei Übergabe

  • C#
  • .NET (FX) 4.0

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    C# OOP Verständnis, GUI, Windows-Form, Probleme bei Übergabe

    Hallo Zusammen,

    ich bin gerade dabei mir das Verständnis an der OOP im Zusammenhang mit GUIs mit C# beizubringen.
    Dafür habe ich ein einfaches Rechnerprogramm geschrieben, welches ganz simpel Brüche erst mal kürzen soll.

    In meiner GUI sind zwei Textboxen zur Eingabe von Zähler und Nenner sowie zwei Buttons zum Kürzen des Bruchs und Beenden der GUI dargestellt.
    Die Klasse Bruch habe ich bereits geschrieben (siehe unten Code),

    Mein Problem ist: Wie soll nun die Übergabe der Werte an die Klasse über das Form und umgekehrt stattfinden.

    Ich dachte dabei an die Implementierung eines Konstruktor, welche die Parameter an die Klasse Bruch übergibt, aber das funktioniert nicht so ganz.

    Kann mir da jemand bitte weiterhelfen. Vielen Dank!


    gruß, akki




    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. namespace Rechner
    6. {
    7. public class Bruch
    8. {
    9. int zaehler,
    10. nenner = 1;
    11. public Bruch(int zaehler, int nenner); // Fehler 1 "Rechner.Bruch.Bruch(int, int)" ist nicht als abstrakt, extern oder partiell gekennzeichnet und muss daher einen Text deklarieren.
    12. //{
    13. //}
    14. public int Zaehler
    15. {
    16. get
    17. {
    18. return zaehler;
    19. }
    20. set
    21. {
    22. zaehler = value;
    23. }
    24. }
    25. public int Nenner
    26. {
    27. get
    28. {
    29. return nenner;
    30. }
    31. set
    32. {
    33. if (value != 0)
    34. nenner = value;
    35. }
    36. }
    37. public void Kuerze()
    38. {
    39. // größten gemeinsamen Teiler mit dem Euklidischen Algorithmus
    40. if (zaehler != 0)
    41. {
    42. int ggt = 0;
    43. int az = Math.Abs(zaehler);
    44. int an = Math.Abs(nenner);
    45. do {
    46. if (az == an)
    47. ggt = az;
    48. else
    49. if (az > an)
    50. az = az - an;
    51. else
    52. an = an - az;
    53. } while (ggt == 0);
    54. zaehler /= ggt;
    55. nenner /= ggt;
    56. }
    57. }
    58. public void Addiere(Bruch b)
    59. {
    60. zaehler = zaehler*b.nenner + b.zaehler*nenner;
    61. nenner = nenner*b.nenner;
    62. Kuerze();
    63. }
    64. }
    65. }



    C#-Quellcode

    1. // Hier beginnt die Form
    2. using System;
    3. using System.Collections.Generic;
    4. using System.ComponentModel;
    5. using System.Data;
    6. using System.Drawing;
    7. using System.Linq;
    8. using System.Text;
    9. using System.Windows.Forms;
    10. namespace Rechner
    11. {
    12. public partial class MainForm : Form
    13. {
    14. public MainForm()
    15. {
    16. InitializeComponent();
    17. }
    18. private void kuerzenButton_Click(object sender, EventArgs e)
    19. {
    20. int zaehler,
    21. nenner = 1;
    22. zaehler = Convert.ToInt32(zaehlerTextBox.Text);
    23. nenner = Convert.ToInt32(nennerTextBox.Text);
    24. Bruch obj1 = new Bruch
    25. (
    26. zaehler,
    27. nenner
    28. );
    29. }
    30. private void beendenButton_Click(object sender, EventArgs e)
    31. {
    32. }
    33. }
    34. }



    C#-Quellcode

    1. // Main : Muss noch bearbeitet werden
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5. using System.Windows.Forms;
    6. namespace Rechner
    7. {
    8. static class Program
    9. {
    10. /// <summary>
    11. /// Der Haupteinstiegspunkt für die Anwendung.
    12. /// </summary>
    13. [STAThread]
    14. static void Main()
    15. {
    16. Application.EnableVisualStyles();
    17. Application.SetCompatibleTextRenderingDefault(false);
    18. Application.Run(new MainForm());
    19. // Bruch b1 = new Bruch(zaehler, nenner), b2 = new Bruch(zaehler, nenner);
    20. //b1.Kuerze();
    21. //b2.Kuerze();
    22. }
    23. }
    24. }

    C#-Quellcode

    1. public Bruch(int zaehler, int nenner); // Fehler 1 "Rechner.Bruch.Bruch(int, int)" ist nicht als abstrakt, extern oder partiell gekennzeichnet und muss daher einen Text deklarieren.
    2. //{
    3. //}

    Jo.
    Du hast eine Methode (in diesem Fall einen Konstruktor) ohne Inhalt deklariert.
    Zur Veranschaulichung:

    C#-Quellcode

    1. public void Foo(); // Methode ohne Inhalt.
    2. public void Foo() // Methode mit Inhalt.
    3. {
    4. // Auszuführender Code.
    5. }


    Bei Methoden ohne Inhalt spricht man im Kontext von Klassen von abstrakten Methoden. Wenn eine Klasse abstrakte Methoden hat, muss auch die Klasse abstrakt sein. Das bedeutet, dass man von ihnen keine Instanz (mit dem new-Operator) erstellen kann. Stattdessen muss es eine Klasse geben, die davon erbt und die diese Methode überschreibt (public override void Foo() { /* Do Stuff */ }). Dann kann man von der Klasse eine Instanz erstellen.

    Dein Konstruktor sollte wohl so aussehen:

    C#-Quellcode

    1. public Bruch(int zaehler, int nenner)
    2. {
    3. Zaehler = zaehler;
    4. Nenner = nenner;
    5. }


    An dieser Stelle einen Tipp: Halte Dich an eine gängige Namenskonvention. Deutsch bei Bezeichnern ist ein No-Go (ist ja eine englische Programmiersprache). Ich schreibe immer so:

    C#-Quellcode

    1. //Das Feld, das für die Property verwendet wird, steht direkt über der Property. Dann hat man alles beisammen.
    2. //Eine gängige Namenskonvention ist es, bei solchen Feldern den Namen mit einem Unterstrich zu beginnen.
    3. private int _Numerator;
    4. public int Numerator
    5. {
    6. get
    7. {
    8. return _Numerator;
    9. }
    10. set
    11. {
    12. _Numerator = value;
    13. }
    14. }
    15. public Fraction(int NewNumerator, ...) //Das "New" vor dem Namen des Parameters ist meine Konvention. Dadurch kann man Feld, Property und Parameter eindeutig auseinanderhalten.
    16. {
    17. Numerator = NewNumerator;
    18. }


    Es gibt auch AutoProperties:

    VB.NET-Quellcode

    1. public int Numerator { get; set; }
    2. public Fraction(int NewNumerator, ...) //Das "New" vor dem Namen des Parameters ist meine Konvention. Dadurch kann man Feld, Property und Parameter eindeutig auseinanderhalten.
    3. {
    4. Numerator = NewNumerator;
    5. }

    Funktioniert prinzipiell genau gleich, braucht aber wesentlich weniger Code und das Feld, das man im Normalfall eh nicht sehen will, wird versteckt.


    Ein Tipp zu OOP noch:
    Brüche (und Zahlen generell) haben keine Identität. ErfinderDesRades hat das mal so in der Richtung erklärt:
    Wenn Du einen Stuhl hast (Typ Stuhl), und von dem die Beinlänge (Property Beinlänge) änderst, dann ist es trotzdem noch der gleiche Stuhl, aber halt mit einer anderen Beinlänge. Stuhl sollte eine Klasse sein.
    Dagegen wenn Du von einem Bruch (Typ Bruch) Zähler oder Nenner änderst (Property Zähler/Nenner), dann ist es ein ganz anderer Bruch, und nicht der selbe Bruch mit anderen Werten. Deshalb sollte Bruch eine Structure sein.

    Mit anderen Worten heißt das, dass Du nicht public class Bruch, sondern public structure Bruch verwenden solltest. Orientiere Dich dabei an System.Drawing.Point.

    Der Unterschied zwischen Klassen und Strukturen ist eigentlich voll einfach, aber voll schwer zu erklären. Ein Beispiel:

    C#-Quellcode

    1. void Test()
    2. {
    3. Bruch a = new Bruch(1, 2); //a ist 1/2
    4. Bruch b = a; //b hat den selben Wert wie a, ist aber nicht a!
    5. a.Zaehler = 5;
    6. Console.WriteLine(b.Zaehler.ToString()); // Gibt trotzdem 1 aus.
    7. }

    Bei der Zuweisung b = a wurde nicht ein Pointer auf einen Bruch kopiert (so wie es bei Klassen gewesen wäre), sondern a enthält direkt den Bruch und bei der Zuweisung wurde der Inhalt des Bruches kopiert.
    Das ist das gleiche wie bei Integern:

    C#-Quellcode

    1. void Test()
    2. {
    3. int a = 1; //a ist 1
    4. int b = a; //b hat den selben Wert wie a, ist aber nicht a!
    5. a = 5;
    6. Console.WriteLine(b.ToString()); // Gibt trotzdem 1 aus.
    7. }
    Nur dass ich hier nicht nur einen Teil von a überschrieben habe (wie beim Bruch nur den Zähler), sondern den ganzen Inhalt von a.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Akki
    Du hast nicht Option Strict On eingestellt...
    Wenn du ein Ergebnis zurrück geben willst, verwende eine Function:

    C#-Quellcode

    1. public double DeineFunction(double Argument1, double Argument2)
    2. {
    3. double Result = 0;
    4. // Berechnungen...
    5. return Result;
    6. }

    Oder hole deine Ergebnisse wieder von den Properties:

    C#-Quellcode

    1. int zaehler = 7;
    2. int nenner = 2;
    3. Bruch obj = new Bruch(zaehler, nenner);
    4. obj.Kuerze();
    5. nenner = obj.Nenner;
    6. zaehler = obj.Zaehler();

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB1963“ ()

    @VB1963
    Wat?
    Bei C# gibt's kein Option Strict Off. Das hat den Blödsinn gar nicht erst dabei.
    Und ich sehe da auch keinen Fall, wo eine Option Strict On Regel verletzt werden würde.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @VB1963
    Ah, ok. Die Zeilen sind OK.
    zaehler /= ggt; ist zaehler = zaehler / ggt;. Und sowohl zaehler (und nenner), als auch ggt sind Integer. In C# funktioniert der /-Operator ein bisschen anders als in VB. Wenn beide Operanden Integer sind, dann wird auch eine Integer-Division durchgführt (in VB wäre das zaehler = zaehler \ ggt, also ein Backslash).

    @Akki
    Die offiziellen Naming Guidelines gibt's hier.
    Beachte, dass in den Guidelines drin steht, dass Parameternamen camelCase verwenden sollten. Ich persönlich bin kein Freund dieser Schreibweise und weil man die beim Verwenden existierender Bibliotheken eigentlich nur liest, aber nie selbst hinschreiben muss, schreibe ich die auch in PascalCase.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hi, @Niko Ortner

    Ich habe da noch eine Frage. Ich habe es soweit programmiert und wollte nun wissen ob es so gut ist oder ob man es noch besser (effizienter) programmieren könnte.

    Hier mein Code:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. namespace Rechner
    6. {
    7. public class Fraction
    8. {
    9. public Fraction(int NewNumerator, int NewDenominator)
    10. {
    11. Numerator = NewNumerator;
    12. Denominator = NewDenominator;
    13. }
    14. public int Numerator{ get; set;}
    15. public int Denominator { get; set; }
    16. public void Reduce()
    17. {
    18. // größten gemeinsamen Teiler mit dem Euklidischen Algorithmus
    19. if (Numerator != 0)
    20. {
    21. int ggt = 0;
    22. int az = Math.Abs(Numerator);
    23. int an = Math.Abs(Denominator);
    24. do {
    25. if (az == an)
    26. ggt = az;
    27. else
    28. if (az > an)
    29. az = az - an;
    30. else
    31. an = an - az;
    32. } while (ggt == 0);
    33. Numerator /= ggt;
    34. Denominator /= ggt;
    35. }
    36. }
    37. public void Addition(Fraction b1)
    38. {
    39. Numerator = Numerator * b1.Denominator + b1.Numerator * Denominator;
    40. Denominator = Denominator * b1.Denominator;
    41. Reduce();
    42. }
    43. }
    44. }


    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Windows.Forms;
    9. namespace Rechner
    10. {
    11. public partial class MainForm : Form
    12. {
    13. public MainForm()
    14. {
    15. InitializeComponent();
    16. }
    17. /// <summary>
    18. /// Reduce the fraction
    19. /// </summary>
    20. /// <param name="sender"></param>
    21. /// <param name="e"></param>
    22. private void reduceButton_Click(object sender, EventArgs e)
    23. {
    24. int numerator1, numerator2,
    25. denominator1 = 1, denominator2 = 1;
    26. numerator1 = Convert.ToInt32(numeratorTextBox.Text);
    27. denominator1 = Convert.ToInt32(denominatorTextBox.Text);
    28. numerator2 = Convert.ToInt32(numerator2TextBox.Text);
    29. denominator2 = Convert.ToInt32(denominator2TextBox.Text);
    30. Fraction obj1 = new Fraction
    31. (
    32. numerator1,
    33. denominator1
    34. );
    35. Fraction obj2 = new Fraction
    36. (
    37. numerator2,
    38. denominator2
    39. );
    40. obj1.Reduce();
    41. denominator1 = obj1.Numerator;
    42. numerator1 = obj1.Denominator;
    43. obj2.Reduce();
    44. denominator2 = obj2.Numerator;
    45. numerator2 = obj2.Denominator;
    46. numeratorTextBox.Text = denominator1.ToString();
    47. denominatorTextBox.Text = numerator1.ToString();
    48. numerator2TextBox.Text = denominator2.ToString();
    49. denominator2TextBox.Text = numerator2.ToString();
    50. }
    51. private void exitButton_Click(object sender, EventArgs e)
    52. {
    53. this.Close();
    54. System.Windows.Forms.Application.Exit();
    55. }
    56. private void additionButton_Click(object sender, EventArgs e)
    57. {
    58. int numerator1, numerator2, numerator,
    59. denominator1 = 1, denominator2 = 1, denominator = 1;
    60. numerator1 = Convert.ToInt32(numeratorTextBox.Text);
    61. denominator1 = Convert.ToInt32(denominatorTextBox.Text);
    62. numerator2 = Convert.ToInt32(numerator2TextBox.Text);
    63. denominator2 = Convert.ToInt32(denominator2TextBox.Text);
    64. Fraction obj1 = new Fraction
    65. (
    66. numerator1,
    67. denominator1
    68. );
    69. Fraction obj2 = new Fraction
    70. (
    71. numerator2,
    72. denominator2
    73. );
    74. obj1.Addition(obj2);
    75. denominator = obj1.Numerator;
    76. numerator = obj1.Denominator;
    77. resultnumeratorTextBox.Text = denominator.ToString();
    78. resultdenominatorTextBox.Text = numerator.ToString();
    79. }
    80. }
    81. }


    Danke schön!
    Sieht prinzipiell richtig aus, soweit.

    Aber man könnte auch ganz anders konzipieren. Ich finde nämlich unschön, dass für jede Rechnung eine neue Klassen-Instanz erstellt wird.

    Wenn mans sophisticated betrachtet, ist ein Bruch kein Dingens, was als Klasse zu designen ist, sondern eine Struct.

    Die Struct wäre ganz einfach, nur die beiden Member: Zähler, Nenner.
    Und es gäbe statische Methoden zum Rechnen mit dem Ding.
    Insbesondere alle möglichen Operator-Überladungen böten sich an - aber das ist erstmal recht advanced.

    Jedenfalls ich will weg von der hier unangemessenen OO-Denke, dass ein Bruch sich selbst berechnet, und hin dazu, dass ein Bruch eine Art Zahl ist, mit der gerechnet wird.



    Zunächstmal jdfs. solltest du Convert.ToInt ersetzen durch Integer.Parse. Denn ersteres ist ziemlich planlos im FW sortiert, während Integer.Parse genau da angelegt ist, wos hingehört: nämlich in der Integer-Struct.
    Und diese Logik kannst du dann auch übernehmen, also deine Bruch-Struct sollte auch eine statische Parse-Methode kriegen, der man sogar 2 strings übergibt, und die daraus den entsprechenden Bruch generiert - inklusive Euklid-Algo.
    Das Ende vom Lied wäre:

    C#-Quellcode

    1. private void additionButton_Click(object sender, EventArgs e)
    2. {
    3. var fraction1=Fraction.Parse(numeratorTextBox.Text, denominatorTextBox.Text);
    4. var fraction2=Fraction.Parse(numerator2TextBox.Text, denominator2TextBox.Text);
    5. var fractionResult=Fraction.Add(fraction1, fraction2);
    6. resultnumeratorTextBox.Text = fractionResult.Numerator.ToString();
    7. resultdenominatorTextBox.Text = fractionResult.Denominator.ToString();
    8. }

    Ok, dann notiere ich mal, was mir auffällt:
    An manchen Stellen ist die Einrückung nicht ganz Bei VisualStudio (zumindest beim 2010-er) ist es bei C# so, dass Du die schließende Klammer eines Blockes löschen und wieder hinschreiben kanns, dann wird der Block und dessen Inhalt korrekt eingerückt.
    Beispielsweise könntest Du bei Code #1 in Zeile 17 die Klammer löschen und wieder hinschreiben, dann wird der Konstruktor richtig eingerückt.
    Oder du könntest in jeder Datei erst mal die allerletzte Klammer neu hinschreiben, dann wird die ganze Datei richtig eingerückt.

    Einrückung ist wichtig. Besonders bei Code #1 Zeile 34. Klammerlose Ifs würde ich generell nur in Ausnahmefällen empfehlen.
    Ich kann bei dem Code nicht sicher sagen, wie die Ifs verschachtelt sind. Meine Vermutung ist das:

    C#-Quellcode

    1. if (az == an)
    2. ggt = az;
    3. else if (az > an)
    4. az = az - an;
    5. else
    6. an = an - az;
    7. // Beziehungsweise mit Klammern:
    8. if (az == an)
    9. {
    10. ggt = az;
    11. }
    12. else if (az > an)
    13. {
    14. az = az - an;
    15. }
    16. else
    17. {
    18. an = an - az;
    19. }
    Meine Konvention mit Ifs ohne Klammer ist die: Wenn nur eine einzige Anweisung ausgeführt werden soll und die Methode verlassen wird, dann so:

    C#-Quellcode

    1. int Foo(Object Bar)
    2. {
    3. if (Bar == null) throw new ArgumentNullException("Bar");
    4. if (Bar.Baz < 0) return -1;
    5. // Dinge mit Bar tun
    6. }



    Die Variablennamen in der Reduce-Methode sind so-lala. Ich bevorzuge lange, aber dafür aussagekräftige Namen, gegenüber kurzen Namen.
    Also würde ich vorschlagen:
    ggt => BiggestCommonDenominator
    az => AbsoluteNumerator
    an => AbsoluteDenominator


    Zu Addition:
    Ich vermute, Du kanntest das einfach noch nicht. In C# kann man operatoren für eigene Datentypen definieren:

    C#-Quellcode

    1. public static Fraction operator +(Fraction Left, Fraction Right)
    2. {
    3. return new Fraction(Left.Numerator * Right.Denominator + Right.Numerator * Left.Denominator,
    4. Left.Denominator * Right.Denominator);
    5. }
    Dann kann man den so verwenden:

    C#-Quellcode

    1. Fraction A = new Fraction(3, 4);
    2. Fraction B = new Fraction(4, 5);
    3. Fraction APlusB = A + B; // Der +-Operator wird aufgerufen.



    In der reduceButton_Click-Methode kannst Du ein bisschen aufräumen. Problematisch ist eigentlich nur die Verwendung von Convert.ToInt32. Ist Dir schon aufgefallen, dass das Programm abschmiert, wenn Du in die Textboxen was eingibst, was keinen Sinn ergibt?
    Dafür gibt's int.TryParse.
    (Kleiner Einschub: Bei C# und VB gibt es sprachspezifische Aliase. Das heißt, man hat einen für die Sprache üblichen Namen, der für einen Typ im .Net Framework steht. Diese sind beispielsweise:

    Quellcode

    1. .Net Typ | C# Name | VB Name
    2. Int16 | short | Short
    3. UInt16 | ushort | UShort
    4. Int32 | int | Integer
    5. UInt32 | uint | UInteger
    6. Int64 | long | Long
    7. UInt64 | ulong | ULong
    8. Single | float | Single
    9. Double | double | Double
    Deshalb ist Int32.TryParse das selbe wie int.TryParse in C# bzw. Integer.TryParse in VB.)
    Der Code könnte dann so aussehen:

    C#-Quellcode

    1. int TempNumerator;
    2. int TempDenominator;
    3. if (!int.TryParse(numeratorTextBox.Text, out TempNumerator))
    4. {
    5. MessageBox.Show("Der Zähler des ersten Bruches ist ungültig.");
    6. return;
    7. }
    8. if (!int.TryParse(denominatorTextBox.Text, out TempDenominator))
    9. {
    10. MessageBox.Show("Der Nenner des ersten Bruches ist ungültig.");
    11. return;
    12. }
    13. var TestFraction1 = new Fraction(TempNumerator, TempDenominator);
    14. if (!int.TryParse(numeratorTextBox.Text, out TempNumerator))
    15. {
    16. MessageBox.Show("Der Zähler des zweiten Bruches ist ungültig.");
    17. return;
    18. }
    19. if (!int.TryParse(denominatorTextBox.Text, out TempDenominator))
    20. {
    21. MessageBox.Show("Der Nenner des zweiten Bruches ist ungültig.");
    22. return;
    23. }
    24. var TestFraction2 = new Fraction(TempNumerator, TempDenominator);
    25. TestFraction1.Reduce();
    26. TestFraction2.Reduce();
    27. numeratorTextBox.Text = TestFraction1.Numerator.ToString();
    28. denominatorTextBox.Text = TestFraction1.Denominator.ToString();
    29. numerator2TextBox.Text = TestFraction2.Numerator.ToString();
    30. denominator2TextBox.Text = TestFraction2.Denominator.ToString();


    Ähnlich in der additionButton_Click-Methode.


    Beim Schließen reicht es übrigens, nur das Fenster zu schließen (mit this.Close();).
    Application.Exit(); verhindert dagegen, dass weiterer Code ausgeführt wird, was üblicherweise benöitigt wird, um Ressourcen zu verwerfen oder z.B. nicht gespeicherte Daten auf Platte zu schreiben, etc.


    Das war es, bis auf die Sache mit struct anstelle von class, aber das ist schon in Ordnung.


    Edit: ErfinderDesRades hat inzwischen auch einiges gepostet, deshalb gehe ich noch darauf ein.
    Die vorgeschlagene Fraction.Parse-Funktion muss davon ausgehen, dass die übergebenen Strings korrekt sind (so wie die Convert.ToInt32-Funktion). Ist das nicht der Fall, muss eine Exception ausgelöst werden.
    Dementsprechend würde sich anbieten, ebenso eine Fraction.TryParse-Funktion anzulegen:

    C#-Quellcode

    1. public static bool TryParse(string NumeratorSource, string DenominatorSource, out Fraction Result)
    2. {
    3. //Pseudocode:
    4. //Wenn NumeratorSource und DenominatorSource zu Integer konvertierbar sind:
    5. //Result zuweisen und true zurückgeben
    6. //Ansonsten:
    7. //(Result auf den Standardwert zuweisen) und false zurückgeben
    8. }


    Wo ErfinderDesRades Fraction.Add stehen hat, würde dann halt wie oben erwähnt die Operator-funktion hinkommen:

    C#-Quellcode

    1. //Aus dem:
    2. var fractionResult = Fraction.Add(fraction1, fraction2);
    3. //Wird das:
    4. var fractionResult = fraction1 + fraction2;
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    Vielleicht mal was zur Reduce-Methode:

    C#-Quellcode

    1. ​private int GCD(int a, int b) {
    2. return (b == 0) ? a : GCD(b, a % b);
    3. }

    und dann bei dem Bruch:

    C#-Quellcode

    1. ​private Fraction Reduce(Fraction f) { //Heißt das nicht Normalize?
    2. var gcd = GCD(f.Nom, f.Denu);
    3. return new Fraction(f.Nom / gcd, f.Denu / gcd);
    4. }
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    Niko Ortner schrieb:

    An manchen Stellen ist die Einrückung nicht ganz Bei VisualStudio (zumindest beim 2010-er) ist es bei C# so, dass Du die schließende Klammer eines Blockes löschen und wieder hinschreiben kanns, dann wird der Block und dessen Inhalt korrekt eingerückt.

    Alternativ geht übrigens auch bei Standardeinstellungen der Shortcut STRG+K, STRG+D, um die gesamte Datei zu formatieren.
    | Keine Fragen per PN oder Skype.