Entwickler-Ecke

C# - Die Sprache - Rückgabewerte - wofür brauche ich sie?


OldCat - Mi 24.11.21 15:54
Titel: Rückgabewerte - wofür brauche ich sie?
Liebe Gemeinschaft,

wieder einmal mehr wende ich mich an euch mit einer grundlegenden Frage, die mir das Internet nicht beantworten kann, wie mir scheint.

Gestern wurde mir klar, ich habe den Sinn von Rückgabewerten in Methoden nicht verstanden. Nach längerer Suche, von den Microsoft.Docs bis "überallhin", fand ich keine Antwort auf die Frage, wofür ich denn ein Rückgabewert nutzen sollte oder gar müsste. Und wann Methoden keinen brauchen.
Zwar lese ich mal mehr mal weniger umständlich formuliert, was Rückgabewerte sind, bzw. was sie tun, doch hat sich für mich nicht der tatsächliche Sinn offenbart.

Mit der Antwort auf die Frage 'wofür brauche ich sie' erhoffe ich mich einen inneren Zugang zu Rückgabewerten in Methoden. Ich habe nur euch, die ich fragen kann.

Mein Frage: 'Warum' und 'wann' sollte ich Rückgabewerte in Methoden nutzen? :?

Liebe Grüße
OldCat


Ralf Jansen - Mi 24.11.21 16:03

Was wäre die Alternative für dich? Bzw. was würdest du den anstatt Rückgabewerte machen? Welchen Anwendungsfall hattest du im Kopf wo das unsinnig erscheint.

Nehmen wir wieder mal was aus dem Framework als Beispiel.
Es gibt da z.b. die Math.Round-Methode. Da geht irgendein Zahlenwert rein kommt ein gerundeter Zahlenwert raus. Wie würdest du diese Methode schreiben wenn es keinen Rückgabewert gäbe?

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


OldCat - Mi 24.11.21 16:57

Zitat:
user profile iconRalf Jansen
Was wäre die Alternative für dich? Bzw. was würdest du den anstatt Rückgabewerte machen? Welchen Anwendungsfall hattest du im Kopf wo das unsinnig erscheint.
Genau da fängt mein Problem schon an: Wenn es nach mir ginge, würde ich wohl immer nur void-Methoden schreiben :gruebel: Da ist in meinem Kopf nur das Zirpen einer einsamen Grille zu hören ... (ergo, Was das Thema angeht: komplette Kopfleere).

Zitat:
user profile iconRalf JansenEs gibt da z.b. die Math.Round-Methode. Da geht irgendein Zahlenwert rein kommt ein gerundeter Zahlenwert raus. Wie würdest du diese Methode schreiben wenn es keinen Rückgabewert gäbe?
Diese Methode war mir bis dato unbekannt. Auch hier ist mir der Sinn nicht klar. (Im Übrigen geht es mir mit Eingabeparametern recht ähnlich).

Und das ist meine Angst: Nie die Notwendigkeit sehen zu können, wann ich selbst einen Rückgabewert für eine Methode brauchen würde, und wann nicht. Daher habe ich jetzt entschieden, ich muss dringend verstehen, wann ich ihn brauche, und wann nicht.
Die Metapher der einsam zirpenden Grille in meinem Kopf muss dringend enden. Die Leere in meinem Kopf, was Rückgabewerte angeht, muss enden.

:nut:

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Ralf Jansen - Mi 24.11.21 17:51

Zitat:
Genau da fängt mein Problem schon an: Wenn es nach mir ginge, würde ich wohl immer nur void-Methoden schreiben

Aber im genannten Beispiel von Math.Round wo wäre da der Sinn wenn die void zurückgibt? Irgendwoher brauchst du doch ein Ergebnis einer Methode.
Manchmal hat man den Fall das eine Methode nur den Zustand einer Klasse ändert dann braucht man keinen Return aber ansonsten ruft man Methoden auf die was verändern und das möchte man doch gern wissen also zurückbekommen. Oder man muß andere Wege haben um an das veränderte zu kommen.

Das mag jetzt wieder so ein blödes "so wie typischerweise Beispiele funktionieren" Problem sein. Weil da der Einfachheithalber direkt ein Ergebnis von irgendwas auf der Console ausgegeben wird und ich es darüber hinaus nirgendwo anders brauche. Das passiert aber so nur in Beispielen. Das passiert nur in den simpelsten Fällen von Code so (aka in Codebeispielen).

Wenn du ein Beispiel brauchst um das zu probieren. Schreibe einen simplen Taschenrechner für die Konsole.
Also Eingabe von zwei Zahlen und einem Operator. Und trenne dabei Aufgaben einigermassen von einander.
Aufgaben wären Eingabe, Berechnung, Ausgabe somit 3 verschiedene Dinge die an 3 verschiedenen Stellen passieren sollen (mindestens 3 verschiedenen Methoden oder sogar Klassen).

Wenn du dabei ohne Parameter, Rückgabewerte oder ähnliches auskommst hast du am Ende möglicherweise Recht und das alles ist unnötig ;)

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


OldCat - Mi 24.11.21 18:28

Zitat:
user profile iconRalf Jansen
Wenn du ein Beispiel brauchst um das zu probieren. Schreibe einen simplen Taschenrechner für die Konsole.
Also Eingabe von zwei Zahlen und einem Operator. Und trenne dabei Aufgaben einingermassen von einander.
Aufgaben wären Eingabe, Berechnung, Ausgabe somit 3 verschiedene Dinge die an 3 verschiedenen Stellen passieren sollen (mindestens 3 verschiedenen Methoden oder sogar Klassen).
Die Aufgabe ist angenommen. Probiere ich umgehend mal aus :zustimm:

Nachtrag: Es fällt mir schwerer als gedacht. Es ist kein Problem die Aufgabe in "einem Wisch" in die Main() Methode zu schreiben ... doch eine andere, mehrere Methoden zu verwenden mit User-Eingabe.
Habe jetzt zwei Quellcodes geschrieben, einen besonders rudimentären und einen mit etwas mehr Code. Doch die Aufgabenstellung ist in beiden nicht gelöst.

Werde wohl länger für ne Antwort brauchen, als gedacht :mrgreen:


OldCat - Sa 27.11.21 17:37

Hätte nie gedacht, dass es mir so große Probleme bereiten würde, einen Taschenrechner zu schreiben, in dem ich beispielsweise drei verschiedene Methoden nutze.
Wirklich zufrieden bin ich mit meinem Code nicht. Er funktioniert immerhin. Das ist mir so die Tage nicht gelungen. Meinen Taschenrechner, den ich zuvor geschrieben hatte, war in der Tat einfach komplett in der Main() Methode geschrieben.
Jetzt habe ich versucht, Eingabe, Verarbeitung und Ausgabe in drei verschieden Methoden zu trennen. Was mich aber jetzt noch stört ist, dass die 'Eingabe Methode' ("CalcInput") in der Main() Methode aufgerufen wird, 'Verarbeitung' und 'Ausgabe' aber innerhalb der 'Eingabe Methode' stehen, da es mir nicht gelungen ist, sie in der Main() Methode aufzurufen.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
namespace ReturnValues_Parameters
{
    internal class Program
    {
        static void Main(string[] args)
        {
            CalcInput();

            System.Console.ReadKey();
        }

        static void CalcInput()
        {
            System.Console.WriteLine("Please type in your first digit.");
            int userInput1 = int.Parse(System.Console.ReadLine());

            System.Console.WriteLine("Please type in your second digit.");
            int userInput2 = int.Parse(System.Console.ReadLine());

            Calculation(userInput1, userInput2);

            CalcOutput(userInput1, userInput2);

        }

        static int Calculation(int a, int b)
        {
            return a + b;
        }

        static void CalcOutput(int userInput1, int userInput2)
        {
            System.Console.WriteLine($"The sum of {userInput1} + {userInput2} = {(userInput1 + userInput2)}");
        }
    }
}


Immerhin habe ich jetzt Übergabeparameter angefangen zu schätzen. Mit den Rückgabewerten fremdel ich allerdings immer noch.


Ralf Jansen - Sa 27.11.21 20:49

Mit der Rückgabe von Calculation() arbeitest du gar nicht sondern berechnest in CalcOutput() neu. Du solltest das was Calculation berechnet auch benutzen. Im Moment könntest du diese Methode auch einfach weglassen. Im Moment ruft Main CalcInput auf die wiederum CalcOutput aufruft. Damit hast du jetzt nur gelernt Parameter über Methoden weiterzureichen. Aber noch nicht die Rückgabe einer Methode zu verwenden.

In Pseudocode habe ich mir die 3-teilung da eher so vorgestellt.


C#-Quelltext
1:
2:
3:
var userInput = CalcInput();
var result = Calculation(userInput);
CalcOutput(result);


Versuch das mal in dieser Richtung zu ändern. Die einzige Hürde jenseits vom benutzen von Methoden deren Parameter und Rückgabewerte ist was ich in Pseudcode userInput genannt habe. Du willst ja zumindest 2 Dinge eingeben (eigentlich 3 wenn du den Operator eingebbar machst und Calculation ein wenig mehr kann als jetzt). Darum ein Hinweis. Hier könnte jetzt eine Klasse helfen die aus den eingegebenen Daten besteht und von der Methode zurückgegeben wird.


jfheins - So 28.11.21 12:19

Möglicherweise verwirrt das jetzt mehr als es hilft, aber ich dachte mir, es wäre einen Versuch wert :)

Zur Frage: "Rückgabewerte - wofür brauche ich sie?" ist die einfache Antwort: Rückgabewerte sind nützlich. Sehr nützlich. Erklärung:

Hier hast du ja schon Funktionen mit Rückgabewerten benutzt:

C#-Quelltext
1:
int userInput2 = int.Parse(System.Console.ReadLine());                    

Weitergedacht könnte man also fragen, wieso haben die Entwickler von .net diese Methode int.Parse() nicht einfach als void Funktion geschrieben= Sodass sie den Wert auf der Konsole ausgibt?
:arrow: Dann wäre die Methode viel weniger nützlich

Da sind es jetzt 2 verschiedene Leute, aber das gleiche passiert auch bei eigenen Methoden - sie sind nützlicher wenn sie Sachen erstmal "leise" machen und zurückgeben als wenn sie alles direkt zur Console ausgeben. Denn man kann den Rückgabewert immer noch später ausgeben, aber man kann schwer etwas, was ausgegeben wurde wieder verstecken.

:arrow: Rückgaben erlauben dir, den Rechencode von dem Ausgabecode zu trennen. Wenn du dann die Ausgabe ändern möchtest, baut man nicht so leicht einen Bug in die Rechnung ein.


Faramir - So 28.11.21 16:25

Der Rückgabewert wird benötigt, wenn Sie etwas in Ihrem Code ersetzen wollen. Ein Beispiel: Ihre Anwendung interagiert mit externen Geräten und Sie erstellen einen Rahmen. In diesen Rahmen wird ein variabler Wert eingegeben und das externe Gerät reagiert auf diesen Wert, z.B. Änderung der Baudrate, 1 - bedeutet 1 MBit und z.B. 2 bedeutet 2 Mbit. Nach einer solchen Drehung wird das Bild an das externe Gerät gesendet.


OlafSt - Mo 29.11.21 08:46

Was, wenn Console.ReadLine() den Wert der Tastatureingabe nicht als Ergebniswert zurückliefern würde?
Wie kämst du dann an den ersten oder zweiten Wert, den der Benutzer eingegeben hat?
Würde ReadLine() die Eingabe des Users auf der Console ausgeben, wäre das bestimmt toll - aber deinen Taschenrechner kannst dann vergessen.

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Palladin007 - Mo 29.11.21 10:22

Vergleich es doch mal mit einer Firma:

Jeder Mitarbeiter hat seinen Arbeitsumfeld und einen konkreten Aufgabenbereich.
Wenn Du als Chef nun einem Mitarbeiter die Aufgabe gibst, er soll z.B. eine Monatsplanung anfertigen, möchtest Du das Ergebnis doch auch haben, oder?
Und Du möchtest auf keinen Fall, dass er sein Ergebnis einfach direkt ins Internet stellt, Du möchtest vorher drüber schauen und selber entscheiden, was Du veröffentlichst und was nicht.


OldCat - Mo 29.11.21 12:17

@user profile iconRalf Jansen

Um sicher zu gehen, dass ich Deinen Pseudocode auch richtig verstehe, schreibe ich meinen bisherigen/obigen Quellcode mal in Pseudocode um. Bitte sag mir, ob ich richtig liege, wenn ja, hilft mir das ungemein. Es ist das erste mal, dass ich von Pseudocode höre :les:
Wenn's erlaubt ist, zeige mir bitte mal, wie mein Quellcode als Pseudocode aussehen würde, falls ich meinen Pseudocode falsch interpretiert habe.


C#-Quelltext
1:
2:
3:
var userInput = CalcInput()
var a, b = Calculation(int a, int b)
Calcoutput(userInput)


@user profile iconjfheinsuser profile iconRalf Jansen
Zitat:
Zur Frage: "Rückgabewerte - wofür brauche ich sie?" ist die einfache Antwort: Rückgabewerte sind nützlich. Sehr nützlich.

Ah okay, wenn ich es richtig verstehe, sind Rückgabewerte nicht zwingend erforderlich, sondern "nur" nützlich.

@ Ralf Jansen: Du hast mich gefragt gehabt, in welchem Code mir Rückgabewerte als überflüssig erscheinen. Dem bin ich noch gar nicht nachgekommen. Möchte das jetzt aber mal nachholen. Es handelt sich hierbei um eine Darstellung von Code, welcher eine Methode mit Rückgabewerte nutzt, um optional das eingeschränkte Volumen eines "Hauses" (Quader-) mit Giebeldach zu berechnen, sofern es kein Flachdach (Quader) besitzt.
Der Code wird vorgestellt in dem Buch "C# Programmieren für Einsteiger" von Michael Bonacina, im Kapitel 9.4: "Methoden mit Rückgabewerten".
Zitat:
Der dort vorgestellte Code ist in deutsch verfasst, ich habe ihn aber in englisch gehalten, da ich eigenen Code grundsätzlich in englisch schreibe. Wenn ich soweit bin, möchte ich dann lernen, meinen Code in verschiedene Sprachen zu portieren.



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
// using System;

namespace ÜbungOOPMethode3
{
    class House
    {
        public int BaseArea;
        public int Height;
        public int WindowAmount;
        public string RoofType;
        public string Color;

        public void SetBaseArea(int baseArea)
        {
            BaseArea = baseArea;
        }

        public void SetHeight(int houseHeight)
        {
            // Das Schlüsselwort 'this' ist optional. Wird aber von Bonacina streng ans Herz gelegt.
            this.Height = houseHeight;
        }

        public void SetWindowAmount(int amountWindows)
        {
            this.WindowAmount = amountWindows;
        }

        public void SetRoofType(string myRoofType)
        {
            this.RoofType = myRoofType;
        }

        public void SetColor(string houseColor)
        {
            this.Color = houseColor;
        }

        public double CalculateVolume()
        {
             double houseVolume = Height * BaseArea;

            if (RoofType == "gabled roof") houseVolume *= 0.75;
            //// System.Console.WriteLine(houseVolume);
            return houseVolume;
            // System.Console.WriteLine(houseVolume);
        }

        public void DisplayHouseValues()
        {
            System.Console.WriteLine("The attributes of my house:\n");
            System.Console.WriteLine($"The base area of that building is: {BaseArea} square meters.");
            System.Console.WriteLine($"The height of that building is: {Height} meters.");
            System.Console.WriteLine($"The amount of windows of that building are: {WindowAmount} windows.");
            System.Console.WriteLine($"The color of that building is: {Color}.");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            House myHouse = new House();

            //myHouse.BaseArea = 1200;
            //myHouse.Height = 20;
            //myHouse.WindowAmount = 100;
            //myHouse.RoofType = "flat roof";
            //myHouse.Color = "greyish white";

            myHouse.SetBaseArea(1200);
            myHouse.SetHeight(20);
            myHouse.SetWindowAmount(100);
            myHouse.SetRoofType("gabled roof");
            myHouse.SetColor("greyish white");

            myHouse.DisplayHouseValues();

            myHouse.CalculateVolume();
            System.Console.WriteLine(myHouse.CalculateVolume());

            //System.Console.WriteLine("The attributes of my house:\n");
            //System.Console.WriteLine($"The base area of that building is: {myHouse.BaseArea} square meters.");
            //System.Console.WriteLine($"The height of that building is: {myHouse.Height} meters.");
            //System.Console.WriteLine($"The amount of windows of that building are: {myHouse.WindowAmount} windows.");
            //System.Console.WriteLine($"The color of that building is: {myHouse.Color}.");

            System.Console.WriteLine("\nPress any key to exit...");
            System.Console.ReadKey();
        }
    }
}


Anschließend habe ich die Methode mit Rückgabewert 'CalculateVolume()' als void Methode verfasst, und das Ergebnis war dasselbe. So kam ich erneut zu dem Schluss, Rückgabewerte in einer Methode sind nicht zwingend notwendig?

Moderiert von user profile iconTh69: Code-Tags durch Quote-Tags ersetzt.


Ralf Jansen - Mo 29.11.21 12:51

In deinem Pseudocode ist Calculation immer noch unnötig. Das was du berechnest willst du auch ausgeben jetzt hast du nur die Ausgabe von CalcInput in CalcOutput geschoben und Calculation wird ignoriert. Du musst schon das was aus Calculation rauskommt im nächsten Schritt verwenden.

Das was du in dem ÜbungOOPMethode3 Beispiel zeigst ist die nächste Ebene der Abstraktion die zeigt wie man den Zustand von Klassen benutzen kann. Ich/wir waren erstmal bei Methoden und wie man die benutzt um Code zu strukturieren. Oder um Begriffe aus der üblichen Literatur zu verwenden wir wahren noch bei reiner strukturierter Programmierung dieses Beispiel ist aber schon objektorientiert.
Eine Methode kann natürlich auch nur den Zustand einer Klasse ändern. Dann ist die Veränderung der Klasse das was aus der Methode rauskommt und nicht der Rückgabeparameter der Methode. Ist aber logisch ähnlich. Methoden machen was und damit man mit dem was die machen irgendwie arbeiten können muss das da irgendwie raus ;)

Und ja letztlich brauch man das alles nicht. Es gibt Programmiersprachen die ohne das alles auskommen und um so näher du an die direkte Hardware rangehst löst sich das ganze eh auf. Es ist eine Erfindung um die Komplexität die im Code dargestellt wird beherrschbar zu machen. Objektorientierte Programmierung ist halt zur Zeit der Goldstandard.

Zitat:
Anschließend habe ich die Methode mit Rückgabewert 'CalculateVolume()' als void Methode verfasst, und das Ergebnis war dasselbe.


Nicht so wie im gezeihten Code. Das hier


C#-Quelltext
1:
System.Console.WriteLine(myHouse.CalculateVolume());                    


kann ohne Rückgabeparameter nicht funktionieren. Denn das was aus CalculateVolume rauskommt geht in WriteLine wieder rein. Void als Typ des Rückgabeparameters würde nicht mal kompilieren.


Th69 - Mo 29.11.21 12:58

Dein Pseudocode ist so aber nicht mehr sinnvoll, denn damit wäre die Berechnungsfunktion überflüssig, da du mittels Calcoutput(userInput) einfach nur die Eingabe wieder ausgeben würdest und nicht die berechneten Werte (a und b).

Und zu deinem 2. Code: bei Änderung des Rückgabetyps der CalculateVolume()-Methode zu void würde aber Console.WriteLine(myHouse.CalculateVolume()) nicht mehr fehlerfrei kompilieren (denn ohne Rückgabe kann auch nichts ausgegeben werden)!

Vllt. verstehst du es anhand des Buches Visual C# 2012 [https://openbook.rheinwerk-verlag.de/visual_csharp_2012/] besser, dort das Kapitel 3.5 Methoden eines Objekts [https://openbook.rheinwerk-verlag.de/visual_csharp_2012/1997_03_005.html#dodtp407a8699-f993-4382-abcb-8bf03a7abe86].


OldCat - Mo 29.11.21 13:45

Huch, den von mir gezeigten Quellcode ist ein Hybrid Code aus dem Bonacina-Buch und meiner Version. Wie das Zustande kommt, verstehe ich nicht.

Daher werde ich die beiden Codebeispiele noch einmal posten und zwar in getrennten Postings:


Hier der Bonacina-Quellcode:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
// using System;

namespace ÜbungOOPMethode3
{
    class House
    {
        public int BaseArea;
        public int Height;
        public int WindowAmount;
        public string RoofType;
        public string Color;

        public void SetBaseArea(int baseArea)
        {
            BaseArea = baseArea;
        }

        public void SetHeight(int houseHeight)
        {
            // Das Schlüsselwort 'this' ist optional. Wird aber von Bonacina streng ans Herz gelegt.
            this.Height = houseHeight;
        }

        public void SetWindowAmount(int amountWindows)
        {
            this.WindowAmount = amountWindows;
        }

        public void SetRoofType(string myRoofType)
        {
            this.RoofType = myRoofType;
        }

        public void SetColor(string houseColor)
        {
            this.Color = houseColor;
        }

        public double CalculateVolume()
        {
             double houseVolume = Height * BaseArea;

            if (RoofType == "gabled roof") houseVolume *= 0.75;
            // System.Console.WriteLine(houseVolume);
            return houseVolume;
            // System.Console.WriteLine(houseVolume);
        }

        public void DisplayHouseValues()
        {
            System.Console.WriteLine("The attributes of my house:\n");
            System.Console.WriteLine($"The base area of that building is: {BaseArea} square meters.");
            System.Console.WriteLine($"The height of that building is: {Height} meters.");
            System.Console.WriteLine($"The amount of windows of that building are: {WindowAmount} windows.");
            System.Console.WriteLine($"The color of that building is: {Color}.");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            House myHouse = new House();

            //myHouse.BaseArea = 1200;
            //myHouse.Height = 20;
            //myHouse.WindowAmount = 100;
            //myHouse.RoofType = "flat roof";
            //myHouse.Color = "greyish white";

            myHouse.SetBaseArea(1200);
            myHouse.SetHeight(20);
            myHouse.SetWindowAmount(100);
            myHouse.SetRoofType("gabled roof");
            myHouse.SetColor("greyish white");

            myHouse.DisplayHouseValues();

            // yHouse.CalculateVolume();
            System.Console.WriteLine(myHouse.CalculateVolume());

            //System.Console.WriteLine("The attributes of my house:\n");
            //System.Console.WriteLine($"The base area of that building is: {myHouse.BaseArea} square meters.");
            //System.Console.WriteLine($"The height of that building is: {myHouse.Height} meters.");
            //System.Console.WriteLine($"The amount of windows of that building are: {myHouse.WindowAmount} windows.");
            //System.Console.WriteLine($"The color of that building is: {myHouse.Color}.");


            System.Console.WriteLine("\nPress any key to exit...");
            System.Console.ReadKey();

        }
    }
}


OldCat - Mo 29.11.21 13:47

Hier meine Version, in der ich das Volumen des Hauses mit Giebeldach ohne Rückgabewert nutze:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
// using System;

namespace ÜbungOOPMethode3
{
    class House
    {
        public int BaseArea;
        public int Height;
        public int WindowAmount;
        public string RoofType;
        public string Color;

        public void SetBaseArea(int baseArea)
        {
            BaseArea = baseArea;
        }

        public void SetHeight(int houseHeight)
        {
            // Das Schlüsselwort 'this' ist optional. Wird aber von Bonacina streng ans Herz gelegt.
            this.Height = houseHeight;
        }

        public void SetWindowAmount(int amountWindows)
        {
            this.WindowAmount = amountWindows;
        }

        public void SetRoofType(string myRoofType)
        {
            this.RoofType = myRoofType;
        }

        public void SetColor(string houseColor)
        {
            this.Color = houseColor;
        }

        public void CalculateVolume()
        {
             double houseVolume = Height * BaseArea;

            if (RoofType == "gabled roof") houseVolume *= 0.75;
            System.Console.WriteLine(houseVolume);
            // return houseVolume;
            // System.Console.WriteLine(houseVolume);
        }

        public void DisplayHouseValues()
        {
            System.Console.WriteLine("The attributes of my house:\n");
            System.Console.WriteLine($"The base area of that building is: {BaseArea} square meters.");
            System.Console.WriteLine($"The height of that building is: {Height} meters.");
            System.Console.WriteLine($"The amount of windows of that building are: {WindowAmount} windows.");
            System.Console.WriteLine($"The color of that building is: {Color}.");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            House myHouse = new House();

            //myHouse.BaseArea = 1200;
            //myHouse.Height = 20;
            //myHouse.WindowAmount = 100;
            //myHouse.RoofType = "flat roof";
            //myHouse.Color = "greyish white";

            myHouse.SetBaseArea(1200);
            myHouse.SetHeight(20);
            myHouse.SetWindowAmount(100);
            myHouse.SetRoofType("gabled roof");
            myHouse.SetColor("greyish white");

            myHouse.DisplayHouseValues();

            myHouse.CalculateVolume();
            // System.Console.WriteLine(myHouse.CalculateVolume());

            //System.Console.WriteLine("The attributes of my house:\n");
            //System.Console.WriteLine($"The base area of that building is: {myHouse.BaseArea} square meters.");
            //System.Console.WriteLine($"The height of that building is: {myHouse.Height} meters.");
            //System.Console.WriteLine($"The amount of windows of that building are: {myHouse.WindowAmount} windows.");
            //System.Console.WriteLine($"The color of that building is: {myHouse.Color}.");


            System.Console.WriteLine("\nPress any key to exit...");
            System.Console.ReadKey();

        }
    }
}


OldCat - Mo 29.11.21 14:00

Zitat:
user profile iconRalf JansenIn deinem Pseudocode ist Calculation immer noch unnötig. Das was du berechnest willst du auch ausgeben jetzt hast du nur die Ausgabe von CalcInput in CalcOutput geschoben und Calculation wird ignoriert. Du musst schon das was aus Calculation rauskommt im nächsten Schritt verwenden.


Oh, da gibt es ein Missverständnis :oops:

Ich mach mal ein repeat:

* Ich schrieb einen extrem rudimentären Code für einen "Taschenrechner".
* Du schriebst Pseudocode, um mir zu zeigen, in welche Richtung mein Code gehen sollte.
* Daraufhin schrieb ich auch Pseudocode, der exakt Deinen Pesudocode auf meinen Taschenrechner spiegeln sollte, um festzustellen, ob ich Deinen Pseudocode überhaupt verstanden habe.

Logischerweise stellt mein Pseudocode nicht eine Lösung, sondern meinen alten Code dar.
Daran knüpfte ich die Frage, ob ich meinen alten Code "der Taschenrechner mit der sinnlosen Rückgabewert-Methode" richtig in Pseudocode umgesetzt habe?
Wenn ja, habe ich Deinen Pseudocode verstanden. Wenn nein, habe ich Deinen Pesudocode nicht verstanden.

C#-Quelltext
1:
2:
if (myPseudocode != yourPseudocode) WriteLine("Old Cat versteht den Pseudocode von Ralf nicht.");
else if (myPseudocode == yourPseudocode) WriteLine("Old Cat kann Ralfs Pseudocode richtig lesen und wird sich an die Umsetzung machen.");

EDIT: Ich möchte mich zwischendurch bei euch allen einmal bedanken, mit welcher Geduld ihr mir helft! Danke an euch alle!! :beer:


Ralf Jansen - Mo 29.11.21 14:12

Ah. Du wolltest den Ist Zustand deines Codes zeigen und nicht wo du hin solltest ;)
In dem Fall passt das ungefähr. Im eigentlichen Code hast du die Ausgabe von Calculation nicht mal irgendwelchen Variablen zugeordnet.
Aber ob du die Rückgabe einer Variablen zuweist und dann ignorierst oder gleich auch die Variable(n) weglässt macht keinen unterschied.


OldCat - Mo 29.11.21 14:18

Zitat:
user profile iconRalf JansenIm eigentlichen Code [...]
Meintest Du damit den Bonacina-Code oder meinen bisherigen Taschenrechner-Code?

PS: Wenn Du den eigentlichen Bonacina-Code meinst:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
public void CalculateVolume()
{
    double houseVolume = Height * BaseArea;

    if (RoofType == "gabled roof") houseVolume *= 0.75;
    System.Console.WriteLine(houseVolume);
    // return houseVolume;
    // System.Console.WriteLine(houseVolume);
}


Schätze ich, Du meinst Height * BaseArea?
Da nutze ich direkt die Felder aus der Klasse.

Meintest Du aber meinen (eigentlichen) Taschenrechner-Code und dort diese Stelle:


C#-Quelltext
1:
2:
3:
4:
static int Calculation(int a, int b)
{
    return a + b;
}


Da dachte ich, dass ich 'a' und 'b' nicht mehr als int kennzeichnen müsste, da sie ja schon als Übergabeparameter "int" sind.


Ralf Jansen - Mo 29.11.21 14:37

Ich meinte deinen Taschenrechner. Die Calculation Methode ist so schon richtig. Der Aufruf der Methode macht aber keinen Sinn wenn man den Return Wert nicht benutzt.
Du hast einfach Calculation(userInput1, userInput2); aufgerufen aber mit dem Ergebnis das aus der Methode fällt nichts gemacht. Du mußt es schon z.b. in einer Variablen ablegen um damit weiterzuarbeiten, so ist es einfach weg.


OldCat - Mo 29.11.21 18:18

Zitat:
user profile iconRalf JansenIch meinte deinen Taschenrechner. Die Calculation Methode ist so schon richtig. Der Aufruf der Methode macht aber keinen Sinn wenn man den Return Wert nicht benutzt.
Du hast einfach Calculation(userInput1, userInput2); aufgerufen aber mit dem Ergebnis das aus der Methode fällt nichts gemacht. Du mußt es schon z.b. in einer Variablen ablegen um damit weiterzuarbeiten, so ist es einfach weg.

Im Quellcode von Michael Bonacina wird bei der 'double HouseVolume()' Methode auch nirgendwo dem Rückgabewert einer Variable zugeordnet? Sollte ich mich jetzt irren: hilf mir bitte, diesbezüglich. Das jedenfalls ist der Grund, warum ich auch keine benutze. Werde aber die von Dir vorgeschlagene result-Variable dafür nutzen. :wink:


OldCat - Mo 29.11.21 18:34

@user profile iconRalf Jansen

Hier mal ein ganz rudimentäres Konstrukt, der mich auf den richtigen Weg bringen soll. Hier habe ich es geschafft, die 'int Calculation()' Methode immerhin richtig einzusetzen...?


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
// using System;

namespace RückgabewerteInMethoden
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int a = 1;
            int b = 2;
            int result = Calculation(b, a);
            System.Console.WriteLine(result);

            System.Console.ReadKey();
        }

        private static int Calculation(int x, int y)
        {
            return x * y;
        }


    }
}


Palladin007 - Mo 29.11.21 19:23

So macht man das, ja.

Jeder Methode erfüllt eine Aufgabe, nur eine.
Eine Methode berechnet etwas und gibt dir das Ergebnis zurück.
Die zweite Methode zeigt das Ergebnis an.
Dafür brauchst Du den Rückgabewert, um das Ergebnis der Berechnung anderswo weiter benutzen zu können, ohne dass Du ständig die Berechnung wiederholen musst..

In diesem Beispiel mag das vielleicht unnötig aussehen, aber z.B. könntest Du auf diese Weise das Ergebnis in der Konsole ausgeben lassen, oder in eine Datei schreiben lassen, um es später automatisch auszuwerten.
Oder Du willst eine richtige Benutzeroberfläche haben, dann könntest Du das Ergebnis dort anzeigen lassen.

Das Entscheidende ist, dass Du dabei die Ausgabe in der Konsole, einer Datei oder einer richtigen Benutzeroberfläche so viel bearbeiten kannst, wie Du willst, die tatsächliche Berechnung bleibt unberührt und Du riskierst keine Fehler, nur weil Du die Ausgabe anpassen willst.

Bei größeren Projekten ist das ganz normal, darauf bauen viele andere Konzepte auf.


jaenicke - Di 30.11.21 09:56

Ein wichtiger Aspekt ist z.B., dass du die Funktion Calculation so einfach in ein anderes Projekt kopieren kannst. Dort wird sie dann einfach funktionieren, weil sie in sich abgeschlossen ist.

Würdest du darin auf Felder deiner Klasse zugreifen, würde das nicht so einfach gehen, weil die in dem anderen Projekt gar nicht existieren. Du müsstest diese also auch hinüberkopieren und einbinden oder deine Funktion an vorhandene Felder anpassen.

Du kannst das vergleichen mit einem Mechaniker, der mit einem Werkzeugwagen irgendwo hingeschickt wird um eine bestimmte Wartung durchzuführen. Er weiß ganz genau was er dafür braucht (wo steht die entsprechende Anlage?) und was er mit seinem Werkzeug machen soll. Und am Ende gibt er eine Wartungsbescheinigung heraus.

Fährt er aber ohne Werkzeugwagen, braucht er vor Ort nicht nur die Angabe wo er hin muss, sondern muss sich auch noch vor Ort fremdes Werkzeug zusammensuchen und sich darauf einstellen. Das ist natürlich weniger effizient und vor allem je nach Umgebung unterschiedlich.


OldCat - Di 30.11.21 11:07

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ein wichtiger Aspekt ist z.B., dass du die Funktion Calculation so einfach in ein anderes Projekt kopieren kannst. Dort wird sie dann einfach funktionieren, weil sie in sich abgeschlossen ist.

Würdest du darin auf Felder deiner Klasse zugreifen, würde das nicht so einfach gehen, weil die in dem anderen Projekt gar nicht existieren. Du müsstest diese also auch hinüberkopieren und einbinden oder deine Funktion an vorhandene Felder anpassen.

Du kannst das vergleichen mit einem Mechaniker, der mit einem Werkzeugwagen irgendwo hingeschickt wird um eine bestimmte Wartung durchzuführen. Er weiß ganz genau was er dafür braucht (wo steht die entsprechende Anlage?) und was er mit seinem Werkzeug machen soll. Und am Ende gibt er eine Wartungsbescheinigung heraus.

Fährt er aber ohne Werkzeugwagen, braucht er vor Ort nicht nur die Angabe wo er hin muss, sondern muss sich auch noch vor Ort fremdes Werkzeug zusammensuchen und sich darauf einstellen. Das ist natürlich weniger effizient und vor allem je nach Umgebung unterschiedlich.
Diese bildliche Veranschauung hat mir sehr weiter geholfen! Das erinnert mich daran, dass auch Ralf Jansen oder Palladin007 etwas von Modularität im Code sprachen. Darauf war ich bisher nicht eingegangen. Muss aber sagen, dass ich Modularität grundsätzlich sehr mag. Daher werde ich jetzt mich an den Taschenrechner setzen, und dabei alle von euch gemachten "Vorgaben" umsetzen:

* Code möglichst modular.
* Der Anwender kann zwischen den arithmetischen Operatoren wählen (ich belasse es erst mal bei den Grundrechenarten).
* Nutzung von Rückgabewerten und Eingabeparametern in Methoden.
* Möglichst das EVA Prinzp anwenden.


OldCat - Di 30.11.21 14:03

Okay, ich habe jetzt einen Taschenrechner programmiert, der die "Vorgaben" von euch einhält (so gut ich es hinbekomen habe).


Ich habe den Quellcode in 5 verschiedene Klassen gegliedert: MainClass, RunProgram, CalcInput, Calculation und CalcOutput.
Leider habe ich immer noch Schwierigkeiten, was die im EVA-Prinzip die Ausgabe (CalcOutput) angeht. Bisher ist die CalcOutput Klasse funktionslos. Die Ausgabe an den Anwender (Ergebnis) wird über eine Anweisung innerhalb der CalcInput Klasse vorgenommen.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
// using System;

// Ich versuche es, Klassen und Methoden modular aufzubauen.
 

namespace Taschenrechner2
{
    internal class MainClass
    {
        static void Main(string[] args)
        {
            RunProgram myCalc = new RunProgram();
            myCalc.Run();
        }
    }
}



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
namespace Taschenrechner2
{
    internal class RunProgram
    {
        private const string AppTitle = "Mini Calculator";
        public void Run()
        {   System.Console.Title = AppTitle;

            System.Console.WriteLine("###############");
            System.Console.WriteLine(AppTitle);
            System.Console.WriteLine("###############\n");

            CalcInput.ChooseInputs();

            System.Console.WriteLine("\nPress any key to exit...");
            System.Console.ReadKey();
        }
    }
}



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
namespace Taschenrechner2
{
    internal class CalcInput
    {
        // NumeralsChoice() und OperatorChoice() zusammelegen, als ChooseInputs()?
        public static void ChooseInputs()
        {
            System.Console.WriteLine("Please enter your first digit: ");
            double digit1 = double.Parse(System.Console.ReadLine());
            System.Console.WriteLine($"You chose: {digit1}");

            System.Console.WriteLine("Please enter your second digit: ");
            double digit2 = double.Parse(System.Console.ReadLine());
            System.Console.WriteLine($"You chose: {digit2}");

            System.Console.WriteLine(@"Choose your operator by number and hit enter:

> 1.) Addition
> 2.) Subtraction
> 3.) Multiplication
> 4.) Division"
);

            int userChoice = int.Parse(System.Console.ReadLine());
            // TODO: switch_case userChoice to either Addition(), Subtraction(), Multiplication() or Division() Methods.

            switch (userChoice)
            {
                case 1:
                    Calculation.Addition(digit1, digit2);
                    break;
                case 2:
                    Calculation.Subtraction(digit1, digit2);
                    break;
                case 3:
                    Calculation.Multiplication(digit1, digit2);
                    break;
                case 4:
                    Calculation.Division(digit1, digit2);
                    break;
            }

            // Hier ist die bisherige Ausgabe:
            System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");
        }
    }
}



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
namespace Taschenrechner2
{
    internal class Calculation
    {
        public static double Addition(double x, double y)
        {
            return x + y;
        }

        public static double Subtraction(double x, double y)
        {
            return x - y;
        }

        public static double Multiplication(double x, double y)
        {
            return x * y;
        }

        public static double Division(double x, double y)
        {
            return x / y;
        }
    }
}


Problem:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
namespace Taschenrechner2
{
    public class CalcOutput
    {
        public static void Results()
        {
            System.Console.WriteLine(Calculation.Addition();
        }
    }
}


Palladin007 - Di 30.11.21 14:11

Spontan sehe ich zwei Probleme:

- Was passiert, wenn man vor dem userChoice-switch einen Wert eingibt, den Du nicht definiert hast?
- Du nutzt wieder nicht die Rückgabewerte der Berechnungsmethoden

Warum nutzt Du nicht wie vorher den Rückgabewert und gibst den aus?


OldCat - Di 30.11.21 14:25

Zitat:
user profile iconPalladin007- Was passiert, wenn man vor dem userChoice-switch einen Wert eingibt, den Du nicht definiert hast?
Danke für den Hinweis! Habe den default case hinzugefügt.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
switch (userChoice)
            {
                case 1:
                    Calculation.Addition(digit1, digit2);
                    break;
                case 2:
                    Calculation.Subtraction(digit1, digit2);
                    break;
                case 3:
                    Calculation.Multiplication(digit1, digit2);
                    break;
                case 4:
                    Calculation.Division(digit1, digit2);
                    break;
                default:
                    System.Console.WriteLine("Your input is invalid. Try again, with numerals 1 - 4.");
                    break;
            }

Jetzt nur noch den Rückgabewert hin bekommen 8)

Sehe gerade, da muss ich auch noch mal ran ... (switch_case default)...


OldCat - Di 30.11.21 15:15

Die revisionierte CalcInput() Methode... sieht das besser aus?


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
namespace Taschenrechner2
{
    internal class CalcInput
    {
        // NumeralsChoice() und OperatorChoice() zusammelegen, als ChooseInputs()?
        public static void ChooseInputs()
        {
            System.Console.WriteLine("Please enter your first digit: ");
            double digit1 = double.Parse(System.Console.ReadLine());
            System.Console.WriteLine($"You chose: {digit1}");

            System.Console.WriteLine("Please enter your second digit: ");
            double digit2 = double.Parse(System.Console.ReadLine());
            System.Console.WriteLine($"You chose: {digit2}");

            System.Console.WriteLine(@"Choose your operator by number and hit enter:

> 1.) Addition
> 2.) Subtraction
> 3.) Multiplication
> 4.) Division"
);

            int userChoice = int.Parse(System.Console.ReadLine());
            // TODO: switch_case userChoice to either Addition(), Subtraction(), Multiplication() or Division() Methods.

            switch (userChoice)
            {
                case 1:
                    Calculation.Addition(digit1, digit2);
                    break;
                case 2:
                    Calculation.Subtraction(digit1, digit2);
                    break;
                case 3:
                    Calculation.Multiplication(digit1, digit2);
                    break;
                case 4:
                    Calculation.Division(digit1, digit2);
                    break;
                default:
                    System.Console.WriteLine("Your input is invalid. Try again, with numerals 1 - 4.");
                    ChooseInputs();
                    break;
            }

            // System.Console.WriteLine(Calculation.Addition(digit1, digit2));
            double result = Calculation.Addition(digit1, digit2);
            System.Console.WriteLine(result);
        }
    }
}


OldCat - Di 30.11.21 15:51

Sollte ich vom Prinzip her nun den Rückgabewert der Addition() Methode richtig verwendet haben, wurmt mich allerdings noch eine Sache gehörig:

Wie bekomme ich "double result" in eine eigene Klasse-> Methode()? Bisher scheitere ich immer an ungültigen Eingabeparameter...


Palladin007 - Di 30.11.21 15:55

Du kannst im Switch auch Variablen zuweisen.
Vorher definieren, im switch zuweisen, danach ausgeben.


OldCat - Di 30.11.21 16:27

user profile iconPalladin007 hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst im Switch auch Variablen zuweisen.
Vorher definieren, im switch zuweisen, danach ausgeben.
Entschuldige, wenn ich jetzt möglicherweise Korinthen kacke, aber meinst Du: definieren = deklarieren & zuweisen = initialisieren? :angel: :hair:

Allerdings kann ich mit dem Hinweis ad hoc nichts anfangen :nixweiss: Durch das Initialisieren von zuvor deklarierten Variablen im switch_case Statement kann ich das Problem lösen? Hmmm...
Falls ich Dich jetzt komplett missverstehe, wäre ich für einen Hinweis dankbar :beer:


Palladin007 - Di 30.11.21 16:36

Zitat:
definieren = deklarieren


Ja - ich dachte, "definieren" klingt einfacher.

Die zwei Wörter "zuweisen" und "initialisieren" sagen aber etwas anderes aus.
Initialisieren ist nur initial, also der erste Wert für die Variable, damit sie überhaupt einen hat. Innerhalb einer Methode ist das notwendig, sonst lässt es der Compiler nicht zu.
Mit Zuweisen meine ich jede weitere Änderung.


OlafSt - Mi 01.12.21 09:43

Ich sehe jetzt, wieso du tatsächlich glaubst, Rückgabewerte sind sinnlos. Denn das Problem, in dem der Hund begraben ist, ist diese Codestelle:


C#-Quelltext
1:
2:
// Hier ist die bisherige Ausgabe:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");


Wie in jedem vorher gezeigten Codebeispiel machst du immer denselben Fehler, der - frei nach Einstein - immer wieder Wahnsinn ist, also unsere Versuche, dir Rückgabewerte klar zu machen, sabotiert.

Ist dir klar, das dein Taschenrechner ausschließlich und nur addieren kann ? Das es vollkommen egal ist, was der Benutzer für eine Rechenoperation wählt, es immer wieder nur eine Addition ist ? Und warum das so ist ? Ist dir klar, das man in solche Ausgaben auch Variablen als Platzhalter schreiben kann, z.B. so:


C#-Quelltext
1:
2:
// Hier ist die bisherige Ausgabe:
System.Console.WriteLine($"The result of your operation is: {myResult}");


Das sollte als Denksanstöße erst mal genügen ;)


Palladin007 - Mi 01.12.21 10:22


C#-Quelltext
1:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");                    

Lustigerweise nutzt Du da auch Rückgabewerte, sogar mehrere ;)
Der Compiler macht nix anderes daraus, als eine Variable mit dem Rückgabewert der Methode zu initialisieren und das dann in den String zu schreiben.

Ergo:


C#-Quelltext
1:
2:
double result = Calculation.Addition(digit1, digit2);
System.Console.WriteLine($"The result of your addition is: {result}");

Und es geht noch weiter:


C#-Quelltext
1:
2:
3:
double result = Calculation.Addition(digit1, digit2);
string message = $"The result of your addition is: {result}";
System.Console.WriteLine(message);

Und das $"" heißt String Interpolation und wird zu Folgendem übersetzt:


C#-Quelltext
1:
2:
3:
double result = Calculation.Addition(digit1, digit2);
string message = string.Format("The result of your addition is: {0}", result);
System.Console.WriteLine(message);

(Noch - mit .NET 6 wurde das grundlegend überarbeitet und wurde sehr viel komplexer, das Ergebnis bleibt aber gleich)

Also wieder ein Rückgabewert - Du nutzt an jeder Ecke und Kante Rückgabewerte und merkst es gar nicht.


OldCat - Mi 01.12.21 17:22

Zitat:
user profile iconOlafSt Ich sehe jetzt, wieso du tatsächlich glaubst, Rückgabewerte sind sinnlos.
Das ist nicht richtig. Ich habe niemals an irgendeiner Stelle behauptet, dass Rückgabewerte sinnlos seien.
Sondern: Ich bin ein Anfänger der Rückgabewerte nicht versteht. Und fragte mehrmals die Frage: Wofür sind Rückgabewerte notwendig, bzw. zwingend notwendig? Wofür brauche ich sie? Wann kann ich sie weg lassen?

Zitat:
Wie in jedem vorher gezeigten Codebeispiel machst du immer denselben Fehler, der - frei nach Einstein - immer wieder Wahnsinn ist, also unsere Versuche, dir Rückgabewerte klar zu machen, sabotiert.
Das vermute ich auch. Und welcher Fehler ist das? Ich sehe ihn ja nicht, den Fehler.

Zitat:
Ist dir klar, das dein Taschenrechner ausschließlich und nur addieren kann ? Das es vollkommen egal ist, was der Benutzer für eine Rechenoperation wählt, es immer wieder nur eine Addition ist ? Und warum das so ist ?

Entschuldigt bitte. Das hätte ich natürlich erwähnen müssen: Ich habe bisher absichtlich nur die Addition implementiert, bis ich das Thema mit den Rückgabewerten richtig vertanden habe und diese auch richtig einsetze. Daher sind die anderen Grundrechenarten erstmal nur //TODO:

##################################################################

Hey Palladin007,
jetzt bin ich doch wieder recht verwirrt:

Wird denn mit:

C#-Quelltext
1:
2:
double result = Calculation.Addition(digit1, digit2);
System.Console.WriteLine($"The result of your addition is: {result}");
... nicht der Rückgabewert der Methode public static int Addition(int x, int y) aus der Calculation Klasse genutzt, wie es sein sollte? Die Frage hatte ich ja weiter oben direkt gestellt. Hatte nur keiner drauf geantwortet.

Hiermit konnte ich jetzt gar nichts anfangen. Das hab ich ja nirgends geschrieben. Was soll mir dieses Beispiel sagen?

C#-Quelltext
1:
2:
3:
double result = Calculation.Addition(digit1, digit2);
string message = $"The result of your addition is: {result}";
System.Console.WriteLine(message)


Zitat:
Also wieder ein Rückgabewert - Du nutzt an jeder Ecke und Kante Rückgabewerte und merkst es gar nicht.
Ja, das ist nicht gut. Wohl deswegen wende ich mich ja auch an euch.

Was also machen wir jetzt mit mir?

Was ist jetzt an meinem Code explizit falsch/fehlerhaft, was die Rückgabewerte angeht?


Palladin007 - Mi 01.12.21 18:01

Das war vielleicht nicht ganz fair.
Ich habe deinen Code mit meinem Wissen über die C#-Technologien auseinander genommen und das geschrieben, was im Hintergrund tatsächlich passiert.
Bei C# passiert viel automatisch oder der Compiler generiert Code, ich wollte dir zeigen, dass Du praktisch nichts machen kannst, ohne direkt oder indirekt Rückgabewerte zu verwenden.

Zitat:
... nicht der Rückgabewert der Methode public static int Addition(int x, int y) aus der Calculation Klasse genutzt, wie es sein sollte?

Das wird sie. Du hattest den Aufruf der Addition-Methode aber direkt im String stehen:


C#-Quelltext
1:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");                    

Beachte den Teil im String in den geschweiften Klammern. Das ist ein Methoden-Aufruf und der Rückgabewert der Methode wird in den String geschrieben.
Hierzu geht der Compiler hin und "schreibt" dafür eine Variable in den Code und verwendet dann die Variable.
Das Ergebnis:


C#-Quelltext
1:
2:
double result = Calculation.Addition(digit1, digit2);
System.Console.WriteLine($"The result of your addition is: {result}");

Vergleich mal die letzten beiden Code-Snippets, sie tun das gleiche, aber beim zweiten Snippet steht die Variable (die sowieso da ist), direkt im Code, sodass Du sie direkt sehen kannst.

Und genau da verwendest Du den Rückgabewert der Addition-Methode.
Du deklarierst eine Variable, initialisierst sie mit dem Rückgabewert deiner Methode und übergibst sie an den String, damit er angezeigt werden kann.
Ohne Rückgabewerte wäre das nicht möglich, wie sollte das Ergebnis der Berechnung sonst in den String kommen?

Zitat:
Hiermit konnte ich jetzt gar nichts anfangen. Das hab ich ja nirgends geschrieben.

Hast Du schon, Du wusstest es nur nicht, das ist das, was der Compiler daraus macht:
Du rufst deine Addition-Methode auf und der Rückgabewert wird an die string.Format-Methode übergeben. Der Rückgabewert davon wird an die Console.WriteLine-Methode übergeben.

Du verwendest also ganz viele Rückgabewerte, ohne es wirklich zu merken.
Jede Methode mit einem Rückgabewert liefert ein Ergebnis zurück, damit Du, ohne diese andere Methode bearbeiten zu müssen, etwas mit dem Ergebnis machen kannst.
Ohne Rückgabewert wäre das nicht möglich.


Th69 - Mi 01.12.21 18:03

So langsam wird dies ein Endlos-Thema. Es kann doch nicht sein, daß du immer noch nicht die gezeigten Code-Beispiele verstehst?

Dein expliziter Fehler in deinem zuletzt gezeigten Taschenrechner-Code ist, daß du zwar in dem switch-Block die Berechnungsmethoden aufrufst, aber eben nicht das zurückgegebene Ergebnis speicherst (und somit diese Aufrufe sinnlos sind - der Compiler diese sogar evtl. eliminiert). Du mußt also eine Zuweisung vornehmen (das, was Palladin007 [https://entwickler-ecke.de/user_Palladin007.html] dir auch mitgeteilt hat)!

Das ist, als wenn du einkaufen gehst, aber die gekauften Lebensmittel beim Markt zurückläßt...


Palladin007 - Mi 01.12.21 18:11

Ich versuchs nochmal.

Folgender Code:


C#-Quelltext
1:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");                    

Daraus wird:


C#-Quelltext
1:
2:
double result = Calculation.Addition(digit1, digit2);
System.Console.WriteLine($"The result of your addition is: {result}");

Daraus wird:


C#-Quelltext
1:
2:
3:
double result = Calculation.Addition(digit1, digit2);
string message = $"The result of your addition is: {result}";
System.Console.WriteLine(message);

Alle drei Snippets sind technisch identisch, sie tun alle das gleiche.

Ganz oben ist dein Code, die beiden anderen Snippets sind die Schritte, was der Compiler aus deinem Code macht, bevor er wirklich kompiliert wird.
Das letzte Snippet ist für dich in diesem Moment nicht so wichtig, ich wollte nur verdeutlichen, dass sich selbst ganz tief versteckt noch Rückgabewerte verstecken.

Wenn ich nun deinen Code mit dem Switch nehme:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
switch (userChoice)
{
    case 1:
        Calculation.Addition(digit1, digit2);
        break;
    case 2:
        Calculation.Subtraction(digit1, digit2);
        break;
    case 3:
        Calculation.Multiplication(digit1, digit2);
        break;
    case 4:
        Calculation.Division(digit1, digit2);
        break;
}

// Hier ist die bisherige Ausgabe:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");

... und die letzte Zeile einmal auseinander nehme:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
switch (userChoice)
{
    case 1:
        Calculation.Addition(digit1, digit2);
        break;
    case 2:
        Calculation.Subtraction(digit1, digit2);
        break;
    case 3:
        Calculation.Multiplication(digit1, digit2);
        break;
    case 4:
        Calculation.Division(digit1, digit2);
        break;
}

// Hier ist die bisherige Ausgabe:
double result = Calculation.Addition(digit1, digit2);
System.Console.WriteLine($"The result of your addition is: {result}");

Und nun sag mir: Wie viel Sinn ergibt bei diesem Code das switch?

Wäre es nicht klüger, die letzte Zeile zu entfernen und das Ergebnis der einzelnen Methodenaufrufe im switch in die Variable und den String zu schreiben?


OldCat - Mi 01.12.21 18:33

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
So langsam wird dies ein Endlos-Thema. Es kann doch nicht sein, daß du immer noch nicht die gezeigten Code-Beispiele verstehst?

Dein expliziter Fehler in deinem zuletzt gezeigten Taschenrechner-Code ist, daß du zwar in dem switch-Block die Berechnungsmethoden aufrufst, aber eben nicht das zurückgegebene Ergebnis speicherst (und somit diese Aufrufe sinnlos sind - der Compiler diese sogar evtl. eliminiert). Du mußt also eine Zuweisung vornehmen (das, was Palladin007 [https://entwickler-ecke.de/user_Palladin007.html] dir auch mitgeteilt hat)! [...]


Okay alles klar, dann beende ich das Thema mal lieber.

Tut mir leid, dass ich so dumm bin. Ich werde mich dann auch erstmal einfach weiter bilden und mich irgendwann zum Thema "Rückgabewerte in Methoden" befassen. Vielleicht macht es bis dahin auch einfach von selbst "klick", während ich für mich weiter lerne. Im Grunde hab ich ja jetzt gelernt, wie man sie schreibt. Und bedingt auch, wofür sie gut sind ... denke ich jedenfalls. Ein paar bestimmte Sätze von euch notiere ich mir zum Thema und dann soll's gut sein.

Ein riesen Dankeschön geht an dieser Stelle an Palladin007, der mir wirklich sehr geholfen hat, bis hier hin. Ein wirklich fettes Dankeschön!! :zustimm:


OlafSt - Do 02.12.21 08:47

Niemand hat behauptet, das du "dumm" seist - und wenn mein Post dem Vorschub geleistet hat, bitte ich um Entschuldigung.

Sich beleidigt dann vom Acker zu machen ist auch nicht sehr zielführend, denn man lernt daraus nichts (außer vielleicht, einer schwierigen Sache aus dem Weg zu gehen). Das Thema mit den Rückgabewerten ist derart essentiell und grundlegend, das du ohne ein solches Verständnis eigentlich gar nicht weiter in Sachen Programmierung weitermachen brauchst. Ähnlich wie in der Grundschule: Wenn du Addition nicht verstanden hast, wirst du Multiplikation erst recht nicht verstehen und somit die ganze Mathematik ein komplettes Rätsel bleiben ;)

Zitat:
Entschuldigt bitte. Das hätte ich natürlich erwähnen müssen: Ich habe bisher absichtlich nur die Addition implementiert, bis ich das Thema mit den Rückgabewerten richtig vertanden habe und diese auch richtig einsetze. Daher sind die anderen Grundrechenarten erstmal nur //TODO:

Dann implementiere die anderen Grundrechenarten auch. Ich bin sehr gespannt zu sehen, wie du das löst.

Zitat:
Und fragte mehrmals die Frage: Wofür sind Rückgabewerte notwendig, bzw. zwingend notwendig? Wofür brauche ich sie? Wann kann ich sie weg lassen?

Das sind mehrere Fragen, aber der Reihe nach:

Rückgabewerte diesen dazu, Ergebnisse, die in einer Programmfunktion errechnet wurden, an die aufrufende Funktion zurückzugeben, so das diese Funktion wiederum mit den Ergebnissen weiter arbeiten kann. Wie grundlegend das ist, mag folgendes Beispiel, aus deinem Code entnommen, aufzeigen:

C#-Quelltext
1:
int userChoice = int.Parse(System.Console.ReadLine());                    


Nehmen wir das Console.ReadLine(). Dieses liefert die Benutzereingabe zurück (!) die gemacht wurde, bis der Benutzer die Entertaste gedrückt hat. Was wäre, wenn Console.ReadLine() nun keine Rückgabewerte hätte - du also die Methode aufrufst, der User "1[Enter]" eintippt und du trotzdem nicht weisst, was der User da eingegeben hat ? Das Console.Readline() liefert ja jetzt nichts mehr zurück, hat ja keinen Rückgabewert mehr.

Du würdest also, ohne den Rückgabewert von Console.Readline() genau gar nichts wissen - außer, das der User ENTER gedrückt hat, denn dein Programm wartet nicht mehr am Aufruf von Console.Readline() :D

Dafür sind Rückgabewerte wichtig.

Nächstes Beispiel ist int.Parse(Console.Readline()), in diesem Fall das Parse. Was könntest du denn int.Parse mitgeben, das es in einen integer umwandeln soll, wenn du von ReadLine() gar nichts zurückbekommst ? Genau: Nix.

Ohne Rückgabewerte ist dein Programm spätestens hier unmöglich zu einer korrekten Funktion zu bringen, denn du weisst ja nicht mal, was der User eingegeben hat. Keine Operatorenauswahl, keine Werte, nichts. Nur, das er Enter gedrückt hat.

Zwingend notwendig sind Rückgabewerte nicht. Es gibt tatsächlich Methoden, die nur eine Operation ausführen, ohne irgendetwas zurückgeben zu können (weil es z.B. sinnlos ist). Console.WriteLine() ist so eine Funktion, denn sie bringt den übergebenen Text zur Anzeige auf die Konsole. Dafür braucht sie nichts zurückgeben, nicht mal ein "war erfolgreich" - denn man geht einfach davon aus, das das mit der Konsole schon klappen wird ;) Womit dann auch die letzte deiner Fragen beantwortet ist.

Was nun deinen Taschenrechner angeht: Es ist schon wichtig zu wissen, was der Benutzer da eingegeben hat. Darum ist Console.ReadLine() eine Funktion mit Rückgabewert. Die Umwandlung in einen integer mit int.Parse ebenfalls, denn es ist die eigentliche Information, die wir haben wollen: Die Usereingabe, aber als integer-Wert.

Auch die Werte deiner Methoden Addition, Subtraktion etcpp. sind wichtige Informationen, liefern sie doch das Ergebnis der vom User gewünschten Operation.


Hilft das vielleicht weiter ?


OldCat - Do 02.12.21 11:07

Zitat:
Niemand hat behauptet, das du "dumm" seist - und wenn mein Post dem Vorschub geleistet hat, bitte ich um Entschuldigung.
Zitat:
Sich beleidigt dann vom Acker zu machen ist auch nicht sehr zielführend, denn man lernt daraus nichts (außer vielleicht, einer schwierigen Sache aus dem Weg zu gehen).
Das Gefühl "ich komme mir dumm vor", kommt natürlich in erster Linie aus mir selbst. Vorschub geleistet hat hier im Forum nur der Post vom Moderator user profile iconTh69
Zitat:
So langsam wird dies ein Endlos-Thema. Es kann doch nicht sein, daß du immer noch nicht die gezeigten Code-Beispiele verstehst?
Der Grund, warum ich dann aber zu dem Schluss kam, den Thread zu beenden, war sein erster Satz "so langsam wird das hier ein Endlosthema". Daraufhin habe ich mal den Begriff "Endlosthema" nachgeschlagen. Es scheint also in zumindest einigen Foren die Regel zu geben, dass Threads so kurz wie möglich sein müssen.
Offensichtlich ist user profile iconTh69 also dieses Thema hier langsam zu lang. Im Grunde habe ich seinen Post so verstanden, dass es jetzt für ihn hier langsam an der Zeit ist, "zum Punkt zu kommen". Da ich mich persönlich aber noch nicht so fühle, als wenn ich diesen Punkt erreicht habe, und die Supervision meines Quellcodes für den Taschenrechner nicht komplett ist, habe ich entschlossen auf Th69 zu hören, und den Thread dann eben zu beenden. Natürlich schwang da in meinem Post eine gehörige Portion Enttäuschung mit...

Also lieber Th69, wenn es auch für Dich okay ist, dass wir das Ding hier zu Ende bringen, wäre ich Dir sehr verbunden! Wenn Du aber sagst, Du möchtest, dass der Thread jetzt sein Ende findet, dann würde ich OlafSt, Ralf Jansen oder Palladin007 fragen, ob es vielleicht per PN oder über einen anderen "Kanal" möglich ist, das Problem zu ende zu bringen. Dort, wo Endlosthreads keine Rolle spielen.
Sollte beides nicht der Fall sein (keine PN oder alternative Kommunikationskanäle, oder Fortführung dieses Threads), bleibt mir ja gar nichts anderes übrig, als "goodbye" zu sagen, aber nur, was diess Thema hier angeht, versteht sich.
Allerdings hätte ich dann wohl in Zukunft immer die Angst, ein zukünftiges Problem nicht schnell genug zu verstehen, wenn ich hier ein neues Thema aufmachen würde... Ist ein persönliches Problem...

@user profile iconOlafSt Okay, ich werde die anderen Grundrechenarten implementieren. Bin selber gespannt, wie ich das wohl lösen werde :lupe:

Je nachdem, wie Th69 über diesen Thread nun entscheidet, und folglich dann Du Dich entscheidest, oder Palladin007 oder Ralf Jansen, wie mit meinem Thema weiter verfahren wird, werde ich Dir/euch gerne das Resultat zeigen. Beziehungsweise mein Verständnis Problem weiter erörtern...

Ich mache mich dann erstmal an den Quellcode... (es ist übrigens mein allerserstes, vollkommen eigenes Programm, das ich schreibe).


Palladin007 - Do 02.12.21 12:22

Ne, keine PN.
Endlos-Themen (:P) sind das Eine, wenn es aber auch nur Einen gibt, der darauf reagieren kann, wird so ein Endlos-Thema schnell anstrengend ;)
Das macht ja den Reiz von so einem Forum aus - abgesehen davon, dass Andere vielleicht ähnliche Schwierigkeiten haben, wie Du.

user profile iconOlafSt hat folgendes geschrieben Zum zitierten Posting springen:
Dann implementiere die anderen Grundrechenarten auch. Ich bin sehr gespannt zu sehen, wie du das löst.

Das solltest Du in der Tat tun.

Wenn Du in deinem Code herausfinden willst, warum Du Rückgabewerte verwenden solltest, dabei aber alles weg lässt, was sie notwendig machst ... naja, Du merkst, das klingt nicht sehr sinnvoll ;)
Also führ das weiter und teste es so, dass Du ohne Code-Änderung (!) immer andere Rechenarten auswählen kannst.

Und noch eine Vorgabe: Nur eine Ausgabe.
Also ein Stück Code, was das Ergebnis ausgibt, egal welche Rechenart ausgewählt wurde.
Also so, wie Du es aktuell hast (am Ende das Console.WriteLine), nur dass es bei jeder Auswahl das richtige Ergebnis ausgibt und nicht nur Addition.


OldCat - Do 02.12.21 14:45

Zitat:
Also führ das weiter und teste es so, dass Du ohne Code-Änderung (!) immer andere Rechenarten auswählen kannst.
Lieber Palladin007, diesen Satz habe ich nicht ganz verstanden. :gruebel: Um die anderen Grundrechenarten zu implementieren, muss ich doch den Code ändern? Meinst Du bestimmten, schon bestehenden Code, den ich nicht ändern soll(te)?


jaenicke - Do 02.12.21 15:01

user profile iconOldCat hat folgendes geschrieben Zum zitierten Posting springen:
Um die anderen Grundrechenarten zu implementieren, muss ich doch den Code ändern?
Damit ist nicht die Implementierung selbst gemeint, sondern die Verwendung danach.

Sprich: Die Rechenart soll durch Eingabe im Programm ausgewählt werden, nicht indem du den Code immer entsprechend änderst. Also so wie bei einem normalen Taschenrechner auch.


OlafSt - Do 02.12.21 15:25

@OldCat: Was das Problem mit dem Verstehen angeht: Das wird dir noch unglaublich oft passieren, gewöhne dich daran ;) Ich programmiere seit 40 Jahren und auch ich stehe hin und wieder da und denke: "Hä ?!?"

Wsa @Palladin007 meinte, ist folgendes: Wenn du dein Programm fortsetzt, wird dir auffallen, das du nur addieren kannst. Willst du also eine Subtraktion oder Division machen, musst du den Code ändern, um das gewünschte Ergebnis zu bekommen.

Und genau diese Code-Herumänderei soll (und darf !) nicht passieren. Du installierst ja auch kein neues Windows, wenn du mal was doppelt anklicken willst :D


OldCat - Do 02.12.21 15:36

Meinen Plan zur "Implementierung" des Codes verrate ich schon mal:

In meinen Augen ist die Implementierung der vier Grundrechenarten in dem von mir gezeigten Code genau genommen ja schon abgeschlossen:
Der Anwender kann ja bereits über die switch case Anweisung eine der vier Grundrechenarten auswählen. Mein Code führt dann ja auch die jeweils gewählte Berechnung bereits aus, und gibt ein Ergebnis zurück. In der Konsole wird aber nur die Addition ausgegeben.
Jetzt suche ich gerade einen Weg, wie in der Variablen double result für alle vier Grundrechenarten das Ergebnis auf der Konsole ausgegeben werden kann. :lupe: Ohne den schon bestehenden Code zu verändern.

Mir ist klar, dass mein Taschenrechner dann nur dazu taugen wird, dass zwei Numerale miteinander verrechnet werden können. Und mein Bauchgefühl sagt mir, dass ich den Code von Anfang an wohl ganz anders hätte aufbauen müssen, um das zu erreichen. :les:


Palladin007 - Do 02.12.21 15:49

user profile iconOldCat hat folgendes geschrieben Zum zitierten Posting springen:
Mein Code führt dann ja auch die jeweils gewählte Berechnung bereits aus, und gibt ein Ergebnis zurück. In der Konsole wird aber nur die Addition ausgegeben.

Weil Du in der Zeile, die in die Konsole schreibst, nochmal die Methode zum Addieren aufrufst.

Dein Code:

C#-Quelltext
1:
System.Console.WriteLine($"The result of your addition is: {Calculation.Addition(digit1, digit2)}");                    

Da rufst Du die Methode nochmal auf, aber immer nur "Addition", egal was vorher ausgewählt wurde.

Die Lösung habe ich vor einer Weile schon geschrieben:

user profile iconPalladin007 hat folgendes geschrieben Zum zitierten Posting springen:
Warum nutzt Du nicht wie vorher den Rückgabewert und gibst den aus?
user profile iconPalladin007 hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst im Switch auch Variablen zuweisen.
Vorher definieren, im switch zuweisen, danach ausgeben.


OldCat - Do 02.12.21 18:43


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
namespace Taschenrechner2
{
    internal class CalcInput
    {
        // private static char userDecision;

        // NumeralsChoice() und OperatorChoice() zusammelegen, als ChooseInputs()?
        public static void ChooseInputs()
        {
            double result = 0;
            char userDecision = default;

            do
            {
                System.Console.WriteLine("Please enter your first digit: ");
                double digit1 = double.Parse(System.Console.ReadLine());
                System.Console.WriteLine($"You chose: {digit1}");

                System.Console.WriteLine("Please enter your second digit: ");
                double digit2 = double.Parse(System.Console.ReadLine());
                System.Console.WriteLine($"You chose: {digit2}");

                System.Console.WriteLine(@"Choose your operator by number and hit enter:

> 1.) Addition
> 2.) Subtraction
> 3.) Multiplication
> 4.) Division"
);

                int userChoice = int.Parse(System.Console.ReadLine());

                // double result = 0;
                // char userDecision;

                switch (userChoice)
                {
                    case 1:
                        result = Calculation.Addition(digit1, digit2);
                        // Calculation.Addition(digit1, digit2);
                        break;
                    case 2:
                        result = Calculation.Subtraction(digit1, digit2);
                        break;
                    case 3:
                        result = Calculation.Multiplication(digit1, digit2);
                        break;
                    case 4:
                        result = Calculation.Division(digit1, digit2);
                        break;
                    default:
                        System.Console.WriteLine("Your input is invalid. Try again, with numerals 1 - 4.");
                        ChooseInputs();
                        break;
                }
                System.Console.WriteLine(result);

                System.Console.WriteLine("Do you like to solve another arithmetical problem? (y/n)");
                userDecision = char.Parse(System.Console.ReadLine());
            } while (userDecision == 'y');
            //System.Console.WriteLine("Please enter your first digit: ");
            //double digit1 = double.Parse(System.Console.ReadLine());
            //System.Console.WriteLine($"You chose: {digit1}");

            //System.Console.WriteLine("Please enter your second digit: ");
            //double digit2 = double.Parse(System.Console.ReadLine());
            //System.Console.WriteLine($"You chose: {digit2}");

            //System.Console.WriteLine(@"Choose your operator by number and hit enter:

//> 1.) Addition
//> 2.) Subtraction
//> 3.) Multiplication
//> 4.) Division");

//            int userChoice = int.Parse(System.Console.ReadLine());

//            double result = 0;

//            switch (userChoice)
//            {
//                case 1:
//                    result = Calculation.Addition(digit1, digit2);
//                    // Calculation.Addition(digit1, digit2);
//                    break;
//                case 2:
//                    result = Calculation.Subtraction(digit1, digit2);
//                    break;
//                case 3:
//                    result = Calculation.Multiplication(digit1, digit2);
//                    break;
//                case 4:
//                    result = Calculation.Division(digit1, digit2);
//                    break;
//                default:
//                    System.Console.WriteLine("Your input is invalid. Try again, with numerals 1 - 4.");
//                    ChooseInputs();
//                    break;
//            }

            //double result = 0;
            //if (userChoice == Calculation.Addition(digit1, digit2)) System.Console.WriteLine(result);
            //// if (Calculation.Addition(digit1, digit2) == 
            //else if (userChoice == Calculation.Subtraction(digit1, digit2)) System.Console.WriteLine(result);
            //else if (userChoice == Calculation.Multiplication(digit1, digit2)) System.Console.WriteLine(result);
            //else if (userChoice == Calculation.Division(digit1, digit2)) System.Console.WriteLine(result);

            // System.Console.WriteLine(Calculation.Addition(digit1, digit2));
            // double result = Calculation.Subtraction(digit1, digit2);
            // System.Console.WriteLine(result);

            // CalcOutput.Results();
        }
    }
}


OldCat - Do 02.12.21 19:20

Hab sogar ne do while Schleife hin bekommen, damit der Anwender anschließend eine neue Eingabe machen kann. :dance2:


Palladin007 - Do 02.12.21 19:25

Teste es doch mal:
Kannst Du einmal starten und dann mehrere unterschiedlichen Berechnungen durchführen?
Und ich sehe auf Anhieb keinen groben Fehler.

Allerdings würde ich es aufsplitten.

Z.B. könntest Du den Inhalt der while-Schleife als eigene Methode herauslösen, die dann alles für genau eine Berechnung (Eingaben, Rechnen, Ausgabe) enthält.
Die zweite Methode enthält die while-Schleife, die Abfrage, ob man weiter machen möchte und den Aufruf der Methode mit der eigentlichen Arbeit.
Du erreichst dann zwei kleinere Methoden, die dadurch übersichtlicher sind.


OldCat - Do 02.12.21 19:44

Grundsätzlich teste ich jeden Code, den ich hier poste. Es wäre mir nichts peinlicher, als hier stolz Code zu zeigen, der dann offenbar dysfunktional wäre :tongue: PS: Und definitiv ist nichts geiler, als Code, der funktioniert :D

Also ja, ich habe den Code auf alle 4 Grundrechenarten angewandt. Sowie den Ausstieg aus dem Code, durch wählen von "n". Der Code funktioniert einwandfrei, und die IDE meckert auch nicht. Alles im Grünen Bereich...

Das bedeutet auch: Ich sehe keinen groben Fehler, egal wie oft ich den Code durchgehe :oops:

Nachtrag: Deine Tipps werde ich mal versuchen umzusetzen. Habe selber auch noch Ideen für den Taschenrechner ... mit nem echten Taschenrechner für 4 Grundrechenarten kann meiner ja noch lange nicht mithalten...


OldCat - Do 02.12.21 21:07

Ach ...(K)einen groben Fehler :rofl: Oh man... wer lesen kann, ist klar im Vorteil :P


OlafSt - Fr 03.12.21 08:36

Was deinen Code angeht: Das ist wie mit dem Korrekturlesen von eigenen Briefen oder Texten. Diese soll man nicht selbst Korrekturlesen, weil man die gemachten Rechtschreib- und Grammatikfehler schlicht nicht sieht. Sowas gibt man immer jemand anderem zum korrigieren.

Ähnlich ist es mit Code: Fehler darin findest du selbst so gut wie nie durch einfaches "immer wieder draufstarren" ;) Der Compiler findet die ganz bösen Dinger wie Tippfehler, Klammerfehler etc., der Debugger dann die logischen Fehler. Wir haben hier im Unternehmen ein 6-Augen-Prinzip eingeführt: Es müssen immer erst zwei weitere Kollegen den Code begutachtet und abgenommen haben, bevor das Zeug in die nächste Version gelangt. Hat sich extrem bewährt ;)

Und ja, es ist ein ausgesprochen cooles Gefühl, sein eigenes Werk nach all der harten Arbeit, dem Fluchen, Lachen und Weinen funktionieren zu sehen - was denkst du, wieso ich das schon 4 Dekaden lang mache ? :D :D :D

Aber nun zur wichtigsten Frage, bevor wir weiter deinen Code perfektionieren :D

Verstehst du nun den Sinn von Rückgabewerten, wofür sie gut sind und wann man sie einsetzt ?

Wenn uns die Antwort gefällt, können wir den Thread hier als abgeschlossen markieren und du kannst einen neuen aufmachen, in dem wir deinen Code weiter aufhübschen :D In Forenthreads gilt dasselbe Prinzip wie in der Programmierung: Nur ein Thema je Aufgabe ;)


Th69 - Fr 03.12.21 09:57

Du hast es also jetzt endlich geschafft, die Rückgabewerte zu benutzen - ich hoffe, du verstehst jetzt deren Bedeutung und Sinn (auf deinen auskommentierten Code, Zeile 101-105, gehe ich jetzt mal diesbzgl. nicht näher ein - ich hoffe aber, du verstehst, war daran syntaktisch und logisch [semantisch] falsch ist?).

Es gibt trotzdem noch einen logischen Fehler - und zwar der rekursive Aufruf von ChooseInputs(): gib mal zuerst eine falsche Operatorauswahl ein (z.B. 5) und danach eine richtige, dann beende die Schleife (mit z.B. n) und beobachte die Ausgabe danach.
Um das zu beheben ist es eben sinnvoll, die einzelnen Codeteile in eigene Methoden zu gliedern (und nur das aufzurufen, was man auch haben will - hier also die Eingabe) - aber hier würde es besser sein, die Schleife zu wiederholen, anstatt der Rekursion.

PS: Der char.Parse-Aufruf ergibt eine FormatException, falls der Benutzer mehrere Zeichen (z.B. "yes" oder "no") eingibt und das sollte es wohl nicht - frag einfach das erste Zeichen ab (falls die Eingabe nicht leer ist) - aber wenigstens hast du ja auch hier den Rückgabewert in einer Variablen gespeichert ;-).

Und so wie OlafSt [https://entwickler-ecke.de/user_OlafSt.html] schon geschrieben, erzeuge für weitere Codeverbesserungen ein neues Thema (kannst aber auf dieses dort verlinken).


OldCat - Fr 03.12.21 15:58

OlafSt hat folgendes geschrieben:
Verstehst du nun den Sinn von Rückgabewerten, wofür sie gut sind und wann man sie einsetzt ?

Wenn uns die Antwort gefällt, können wir den Thread hier als abgeschlossen markieren und du kannst einen neuen aufmachen, in dem wir deinen Code weiter aufhübschen :D In Forenthreads gilt dasselbe Prinzip wie in der Programmierung: Nur ein Thema je Aufgabe


Ja, selbst gehe ich davon aus, dass ich den Sinn von Rückgabewerten verstanden habe. Ich versuche es mal mit meinen eigenen Worten zu beschreiben, statt Gelesenes einfach abzuspulen:

Zu Beginn fragte ich mich, ob Rückgabewerte denn zwingend notwendig seien, da ich selbst keine zwingende Notwendigkeit sah. Diese Beobachtung hat sich auch als richtig herausgestellt.
Rückgabewerte sind zwar nicht zwingend notwendig, und doch besitzen sie eine gewisse "Essenzialität". Ich kann mit Rückgabewerten den Code übersichtlicher/kompakter und modularer/wiederverwendbarer gestalten. Rückgabewerte helfen mir bei der "Kommunikation zwischen Klassen". Es wurde mir auch gesagt, dass Rückgabewerte Teil des Paradigmas des objektorientierten Programmierens ist. Selbst habe ich nie eine Programmiersprache gesehen oder gelernt, die nicht dem Paradigma des ooP folgt. Daher kann ich das nicht beurteilen. Aber ich merke es schon, da ich ja mit Rückgabewerten, Methoden aus verschiedenen Klassen miteinander kommunizieren lassen kann. (Methode() xy aus Klasse zz tut etwas und gibt einen Wert zurück. Es gibt einen Wert an eine Methode oder Anweisung zurück, welche eben diese Methode() xy aus Klasse zz aufruft).

Das ist dies, was ich jetzt als Start im Thema Rückgabewerte meine verstanden zu haben. Zu Beginn dieses Threads hätte ich immer nur void Methoden geschrieben. Doch jetzt würde ich immer wo ich kann, mit Rückgabewerten an bestimmte "Aufrufer" verwenden, da es den Code eine gewisse "Flexibilität" gibt...

:hair:

Moderiert von user profile iconTh69: Beiträge zusammengefasst

PS: Alles Weitere, wenn ich die Prüfung "Rückgabewerte" bestanden habe, dann in einem neuen Thread :flehan:

Moderiert von user profile iconTh69: C# durch Quote-Tags ersetzt.


OldCat - Sa 04.12.21 10:53

Hmmm ... gehe ich richtig der Annahme, dass meine Worte zum Thema "Rückgabewerte" missfallen erregt haben? Oder bin ich jetzt einfach zu ungeduldig, eure Antwort abzuwarten?

Wenn ich "versagt" haben sollte, und ihr darin keinen Sinn mehr seht, an mir Zeit zu verschwenden, dann wäre es mir lieb, wenn ihr mir das sagt.
Dann weiß ich, woran ich bin.


Th69 - Sa 04.12.21 12:53

Es liest sich jetzt halbwegs schlüssig, aber ob du das wirklich verstanden hast, zeigt eigentlich nur die weitere Praxis.
Daher verbessere deinen Code entsprechend des Vorschlags von Ralf Jansen [https://entwickler-ecke.de/user_Ralf%2520Jansen.html]:

C#-Quelltext
1:
2:
3:
var userInput = CalcInput();
var result = Calculation(userInput);
CalcOutput(result);


Eine der wichtigsten Regeln beim (professionellen) Programmieren lautet nämlich: Trennung von IO (Eingabe, Ausgabe) und Logik.
Die Logik-Klassen (bzw. Methoden) sollten so erstellt werden, daß sie unabhängig von deren Benutzung sind (also z.B. in welchem Projekttyp sie verwendet werden).

Für die Übergabe mehrerer Rückgabewerte kannst du entweder eine eigene Klasse (oder Struktur)

C#-Quelltext
1:
2:
3:
4:
5:
class UserInputs
{
  public double number1, number2;
  // ...
}

oder aber die Tuple [https://docs.microsoft.com/de-de/dotnet/api/system.tuple?view=net-6.0]-Klasse benutzen:

C#-Quelltext
1:
Tuple<doubledouble>                    

(diese haben aber den Nachteil, daß man die Eigenschaftsnamen ItemX nicht selber benennen kann)
Alternativ gingen auch noch sog. Ouput-Parameter [https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/out-parameter-modifier] (nur der Vollständigkeit halber).


OldCat - Sa 04.12.21 13:43

Th69 hat folgendes geschrieben:
Es liest sich jetzt halbwegs schlüssig, aber ob du das wirklich verstanden hast, zeigt eigentlich nur die weitere Praxis.


Okay, dann ist damit dieser Thread im Grunde abgehakt. Das "Taschenrechner" Projekt werde ich mit Verweis auf diesen Thread, wie gemeinsam besprochen, in einem neuen Thema behandeln.


Palladin007 - Sa 04.12.21 15:12

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:

oder aber die Tuple [https://docs.microsoft.com/de-de/dotnet/api/system.tuple?view=net-6.0]-Klasse benutzen:

C#-Quelltext
1:
Tuple<doubledouble>                    

(diese haben aber den Nachteil, daß man die Eigenschaftsnamen ItemX nicht selber benennen kann)
Alternativ gingen auch noch sog. Ouput-Parameter [https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/out-parameter-modifier] (nur der Vollständigkeit halber).

Bitte kein Tuple :/
Die Dinger sind sehr oft ein Zeichen für schlechten Code - selbst wenn man deinen schon genannten Nachteil ignoriert.

Wenn unbedingt Tuple sein muss, dann lieber ValueTuples [https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/builtin-types/value-tuples].
Die können immer noch ein Zeichen für schlechten Code sein, aber man hat nicht mehr den Nachteil der fehlenden Namen.
Ich nutze sie ganz gerne innerhalb einer Klasse für private-Methoden oder innerhalb einer Methode selber für fortgeschrittene Themen wie z.B. LINQ. Nimm das aber überhand, schreibe ich auch dafür eine Klasse.

Am besten wäre aber, Du überlegst dir, ob das nicht generell ein Zeichen dafür ist, dass die Methode zu viel macht.
Es gibt ein paar Ausnahmen, die brauchen zwingend mehrere Rückgabewerte, aber die sind eben nur das: Ausnahmen.
Oder, wenn es wirklich nicht anders geht, dann wäre eine eigene Klasse angebracht.

Die gleiche Frage muss man sich bei out-Parametern natürlich auch stellen, es ist nur anderer Weg, das gleiche Problem (mehrere Rückgabewerte) zu lösen.
Aber gerade bei den eben erwähnten Ausnahmen (z.B. die ganzen TryParse-Methoden) sind out-Parameter eine nützliche Sache, da sie z.B. im if ein paar Vorteile bringen.

Bei allen diesen Wegen sollte man sich sicher sein, wenn man sie nutzt, ansonsten riskiert man langfristig sehr chaotischen Code.


Ralf Jansen - Sa 04.12.21 16:48

Zitat:
Aber gerade bei den eben erwähnten Ausnahmen (z.B. die ganzen TryParse-Methoden) sind out-Parameter eine nützliche Sache, da sie z.B. im if ein paar Vorteile bringen.

Und dann schreibt man asynchronen Code wo out Parameter nicht mehr erlaubt sind und man ist zurück bei Tuples.

Aber um im Context zu bleiben. Hier geht es ja darum um einen Anfänger an die Basics heranzuführen. Da gibt es vieles drum herum was man erstmal Wissen muss um diese Dinge richtig einzusetzen. Die meisten Features gibt es in der Sprache weil sie auch einen gültigen Einsatzort haben. @OldCat du solltest die gefallen Begriffe erstmal ignorieren. Tuple, out Parameter etc. kommen erst viel später und verwirren jetzt nur.


Palladin007 - Sa 04.12.21 16:55

Ja natürlich gibt es auch für ValueTuples gute Einsatzorte, aber die muss man auch erst erkennen lernen.
Wobei ich bei einem TryXYZAsync-Methoden eher zu einem eigenen Struct tendieren würde, das bietet mehr Möglichkeiten mit Nullable reference types und den Annotations dazu.


Aber für einen Anfänger ist es in jedem Fall klüger, diese Themen erst mal links liegen zu lassen.
ValueTuples sind zwar einfach zu nutzen, aber sehr schwer, *richtig* einzusetzen - und die anderen Themen sind schwieriger zu nutzen *und* schwierig, *richtig* einzusetzen.


OlafSt - Mo 06.12.21 09:23

Ich denke auch, wir sollten es bei den einfachen Rückgabewerten belassen (die ja so weit erst mal verstanden sind) und @Oldcat erstmal damit zurechtkommen lassen. Damit deckt man 99,95% aller Fälle im Code ab und für die Spezialfälle gibts dann ne Sonderlektion :D


OldCat - Mo 06.12.21 11:40

Hey Leute :wave:

Wenn ihr Lust habt, könnt ihr ja hierher wechseln: Grundlagen OOP - Projekt Taschenrechner [https://entwickler-ecke.de/topic_Grundlagen+OOP++Projekt+Taschenrechner_118866.html].

Palladin007 hat schon mal vorgelegt und sich den aktuellen Taschenrechnercode angeschaut... ^_^