Zum Inhalt springen

nicht zugewiesene Variablen


Gewinde

Empfohlene Beiträge

Guten Abend,

so da bin ich mal wieder. Ich gehe derzeit einiges aus meinem Grundkurs nochmal durch, um etwas mehr Sicherheit im Umgang mit Code zu bekommen. Wärend meiner Übungen merkte ich immer wieder, dass ich zwar die einzelnen Möglichkeiten welche mir C# bietet verstehe, diese allerdings in einem komplexen Programm nicht wirklich anwenden konnte. Wie auch im Handwerk ist die Praxis dann meist doch schwerer als die Theorie. ;)

Bei meinen Übungen mit Delegaten bin ich auf ein kleines Problem gestoßen. VS gibt mir bei diesem Code immer den Fehler calculate nicht zugewiesen (im code unterstrichen). In meinem Buch oder auch in anderen Büchern wird dies allerdings auch genau so angegeben und bei denen soll der code so funktionieren. Ich weis das man mit Variablen bezüglich Klammern acht geben muss, doch in meinen Augen müsste dieser Code eigentlich so funktionieren.

Ich bekomme den Code nur zum Laufen, wenn der gesamte untere Teil in die einzelnen if statements rutscht (außer die Methoden natürlich). in meinen Augen wird calculate oben declariert und in den if statements inizialisiert und dann unten in der variable result gespeichert und über console.writeline ausgegeben.

 

    public delegate int Calculation(int num1, int num2);

    internal class Program
    {
        static void Main(string[] args)
        {
            Calculation calculate;
            int result;
            string input;

            Console.Write("Zahl1: ");
            int num1 = Convert.ToInt32(Console.ReadLine());
            Console.Write("Zahl2: ");
            int num2 = Convert.ToInt32(Console.ReadLine());

            Console.Write("Add [1] Sub [2]");
            input = Console.ReadLine();

            if(input == "1")
            {
                calculate = new Calculation(Addition);
            }
            else if(input == "2")
            {
                calculate = new Calculation(Subtraction);
            }

            result = calculate (num1, num2);

            Console.WriteLine(result);

            Console.ReadKey();
        }

        static int Addition(int num1, int num2)
        {
            return numb1 + numb2;
        }

        static int Subtraction(int num1, int num2)
        {
            return num1 - num2;
        }

dankeschön :)

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 9 Minuten schrieb Gewinde:

in meinen Augen wird calculate oben declariert und in den if statements inizialisiert und dann unten in der variable result gespeichert und über console.writeline ausgegeben.

Richtig, was passiert aber, wenn input weder "1", noch "2" ist? Dann würde calculate nicht zugewiesen werden, daher kommt auch der Fehler "calculate nicht zugewiesen". Du musst also sicherstellen, dass calculate in dem Kontext, in dem du es in eine Variable speichern möchtest, auch initialisiert wurde.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 3 Wochen später...

Hallo zusammen,

ich verwende für mein derzeitiges Problem mal einfach meinen alten Post. Da ich mittlerweile leider nur sehr selten zum lernen komme, bin ich in meinem Wissensstand auch nur sehr wenig weiter gekommen.

Also folgendes, das Problem an sich wurde oben schon beschrieben und die Lösung dazu ist mir soweit auch bekannt. Wenn ich eine Variable habe, welche z.B. über eine switch Anweisung inizialisiert werden soll, muss ich sicherstellen, daß diese am Ende der Anweisung auch wirklich eine Inizialisierung erhalten hat.

Meine while-Schleife ist ein Teil einer Methode, in welcher der Nutzer nach seiner gewünschten Rasse abgefragt werden soll. in der Methode werden am Anfang die Variablen string userInput, bool correctInput = true und Breed breedChoice deklariert.

Am ende der Schleife soll das ganze in einer anderen Methode verarbeitet und dort zur Erstellung eines neuen Character objects verwendet werden.

In meinem Switchblock wird die variable breedChoice verarbeitet und über die Eingabe zugewiesen. Da der ein oder andere Nutzer sicher mal die falsche Taste drücken wird, soll über default sichergestellt werden, das die Abfrage so lange dauert, bis dem Benutzer ein Licht aufgeht und er nur Zahlen von 1-5 nutzt.

Logischerweise wird im defaultblock keine Zuweisung getätigt, das es sich dabei ja um keine korrekte Zuweisung handelt. Dadurch gibt es im return auch einen Fehler zwecks nicht zugewiesener Variable. Meine Lösung war es nun, die breedChoice Variable im default einfach die Zuweisung Mensch zugeben ( da die while-Schleife eh weiterlaufen würde, müsste diese Zuweisung eh solange geändert werden, bis ein korrekte eingabe getätigt wurde.) Damit ist dann zumindest der compiler zufrieden. Für mich stellt sich jetzt die Frage, ob ich damit zufrieden sein kann, da es ja eigentlich nicht wirklich mein Gedankenansatz wäre (bzw. saubere Programmierung wäre.).

Ich habe in microsoft.docs einen Verweis auf die Nutzung von delegaten gelesen, allerdings bin ich mir auch da nicht wirklich sicher ob dies die korrekte Lösung wäre.

            while (true)
            {
                Console.WriteLine("Welcher Rasse gehört dein Charakter an?\n");
                Console.WriteLine("[1] Mensch");
                Console.WriteLine("[2] Troll");
                Console.WriteLine("[3] Ork");
                Console.WriteLine("[4] Elf");
                Console.WriteLine("[5] Zwerg\n");
                Console.Write("Eingabe: ");

                userInput= Console.ReadLine();

                switch (userInput)
                {
                    case "1":
                        breedChoice = Breed.Mensch;
                        break;
                    case "2":
                        breedChoice = Breed.Troll;
                        break;
                    case "3":
                        breedChoice = Breed.Ork;
                        break;
                    case "4":  
                        breedChoice = Breed.Elf;
                        break;
                    case "5":
                        breedChoice = Breed.Zwerg;
                        break;
                    default:
                        correctInput = false;
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("FEHLER: Ungültige Eingabe");
                        System.Threading.Thread.Sleep(500);
                        Console.ForegroundColor = ConsoleColor.White;
                        break;

                }
                if (correctInput)
                {
                    break;
                }
            }

            return breedChoice;
        }

Link zu diesem Kommentar
Auf anderen Seiten teilen

  1. Eine Endlosschleife ist erstmal keine gute Idee, da der Abbruch der Schleife doch bekannt ist. Also würde ich sie auch so definieren.
  2. Die Switch-Anweisung würde ich in eine separate Methode packen, um den Code der Schleife kompakt zu halten. Dafür gibt es auch inzwischen eine recht kompakte Syntax. Der Vorteil ist auch dann, dass man diesen Code-Teil automatisiert testen könnte.
  3. Schaue dir mal nullable-Wertetypen an. Damit ließe sich eine recht gute möglichkeit bauen. Anstatt im default-Zweig ein boolean zu setzen, könnte man breedChoice auch null zuweisen und die Schleife läuft solange, bis breedChoice ungleich null ist.

So würde ich dies auf die Schnelle lösen:

static void Main()
{
  Console.WriteLine(GetBreed());
}

static Breed GetBreed()
{
  Breed? breed = null;
  while (breed == null)
  {
    Console.WriteLine("Welcher Rasse gehört dein Charakter an?\n");
    Console.WriteLine("[1] Mensch");
    Console.WriteLine("[2] Troll");
    Console.WriteLine("[3] Ork");
    Console.WriteLine("[4] Elf");
    Console.WriteLine("[5] Zwerg\n");
    Console.Write("Eingabe: ");
    
    var input = Console.ReadLine();
    breed = ToBreed(input);
    
    if(breed == null)
    {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("FEHLER: Ungültige Eingabe");
      Console.ResetColor();
    }
  }
  return breed.Value;
}

static Breed? ToBreed(string? input)
  => input switch
  {
    "1" => Breed.Mensch,
    "2" => Breed.Troll,
    "3" => Breed.Elf,
    "4" => Breed.Zwerg,
    _ => null
  };

Natürlich ist jetzt nicht alles perfekt aber ich denke, es zeigt, in welche Richtung es geht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Super, dankeschön an euch beide. Das mit der Schleife habe ich in den Übungsaufgaben in meinem Programmierkurs so gelernt. Allerdings muss ich zugeben klingt deine Variante sehr wohl sinniger und auch eleganter. Nullable hatte ich versucht, bin aber leider daran verzweifelt, wobei ich darüber noch nicht viel gelernt habe und wahrscheinlich darum auch nicht damit zur Lösung gekommen bin. Ich hatte noch eine Idee gehabt und wollte meinen Post editieren (auch um Rechtschreibfehler zu minimieren) hatte aber irgendwie nicht funktioniert. Ich hatte überlegt dem Enum eine weitere Option hinzuzufügen und damit die breedChoice als Diverse zu initialisieren und hinterher dann mit dem Switchblock abzuändern und dann als nicht diverse zu übergeben. Ob das so korrekt gewesen wäre, bzw. ob dies sauberer Code gewesen wäre weiß ich allerdings nicht. Der Compiler wäre damit zumindest zufrieden gewesen.

Ich werde die Idee mit nullable mal ausarbeiten und die angegebenen möglichkeiten von euch aufnehmen und für mich übernehmen.

Danke an euch für die schnelle und gute Hilfe 👍, wenn es soweit ist werde ich das ergebnis hier mal zur Schau stellen. 🙂

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 1 Minute schrieb Gewinde:

Ich hatte überlegt dem Enum eine weitere Option hinzuzufügen und damit die breedChoice als Diverse zu initialisieren und hinterher dann mit dem Switchblock abzuändern und dann als nicht diverse zu übergeben.

Davon würde ich abraten, weil man einen Störfaktor implementiert, den man ja eigentlich nicht haben möchte. Man schleppt dann durch die Anwendung einen Wert, der nicht zulässig ist und nur an einer Stelle gebraucht wird.

Was auch noch ginge, wäre ein Wert außerhalb des Wertebereichs des Enums festzulegen. Ein Enum ist ja im Grunde nur eine Repräsentation einer Zahl. Du kannst also jede Ganzzahl in ein Enum casten. Man könnte also eine Zahl als einen ungültigen Wert bestimmen und mit der IsDefine()-Methode aus der Enum-Klasse könntest du schauen, ob der ermittelte Wert im Enum definiert ist. Im Beispiel hab ich die -1 als ungültige Zahl ausgesucht:

public enum Breed
{
  Mensch = 1,
  Troll,
  Elf,
  Zwerg
}

Breed breed = (Breed) (-1);
Console.WriteLine(Enum.IsDefined(breed)); // gibt false zurück, da -1 nicht im Enum definiert ist.

Allerdings halte ich die nullable-Variante für besser, denn wenn man doch mal -1 in das Enum hinzufügt, kann man Probleme bekommen, weil man dann alle Stellen im Code suchen muss, die -1 als ungültigen Wert voraussetzen. Der ungültige Wert erzeugt somit wieder ein Störfaktor in der ganzen Anwendung. Die nullable-Variante konzentriert sich aber auf einen genauen Punkt in der Anwendung und streut nicht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe die Variante, welche du als erstes beschrieben hast genommen und werde diese auch so für weitere Projekte weiter verfolgen. Ich habe im gleichen Atemzug die Abfrage des Charakternamens überarbeitet um die Dauerschleife dort gleich mit zu entfernen. Meine switch-Anweisung ist allerdings die weniger elegantere geworden, einfach weil ich erstmal das Grundprinziep zwecks Verständnis beibehalten möchte. Ich habe diese auch als eigene Methode in die Klasse integriert und nicht static gemacht, wobei mir der Sin der dahinter steckt bewußt ist und auch einleuchtet. Ich werde die Klasse einfach mal posten, denn diese sollte soweit fertig sein, bis auf die spätere Serialisierung, die fehlt im moment noch. Bei dieser wollte ich erstmal Binaryformatter benutzen, obwohl ich gelesen habe das man diesen nicht mehr verwenden sollte/darf. Im Internet habe ich etwas über json oder auch xml gelesen, wobei ich damit noch komplett keine Erfahrung gemacht habe. Ich wüßte bei den vielen Möglichkeiten derzeit auch noch nicht was das sinvollste wäre, in meinem Fall soll es sich ja süäter erstmal nur um ein kleines Konsolen Textadventure handeln. XAML wollte ich erst nach Abschluss dieses Projekts beginnen.

Ich danke euch nochmal für eure tolle Hilfe :)

 internal class CharacterCreator : StartMenu
    {
        //Einleitung der Menüführung

        public override void DisplayMenu()
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("************************");
            Console.WriteLine("*                        *");
            Console.WriteLine("* Charaktererschaffung *");
            Console.WriteLine("*                        *");
            Console.WriteLine("************************\n");
            Console.ResetColor();

            CreateCharacter();
        }

        //Erstellung eines neuen Charakters

        private Character CreateCharacter()
        {
            string charName = GetName();
            Breed charBreed = GetBreed();

            Character character = new Character(charName, charBreed);

            return character;

        }

        //Abfrage der Namenseingabe des Benutzers

        private string GetName()
        {
            string input = "";
            bool correctInput = false;

            while (!correctInput)
            {
                Console.WriteLine("Wie soll dein Charakter heißen?\n");
                Console.Write("Eingabe: ");
                input = Console.ReadLine();

                ValidateName(input);

                if (ValidateName(input))
                {
                    correctInput = true;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("FEHLER: Ungültiger Name");
                    System.Threading.Thread.Sleep(500);
                    Console.ForegroundColor = ConsoleColor.White;
                }
            }

            return input;
        }

        //Namenseingabe wird auf Existens und Sonderzeichen überprüft

        private bool ValidateName(string name)
        {
            if (CharacterManager.CheckIfCharacterExists(name))
                return false;

            foreach(char c in name)
            {
                if (!char.IsLetterOrDigit(c))
                {
                    return false;
                }
            }

            return true;
        }

        //Abfrage der Breed Eingabe

        private Breed GetBreed()
        {
            Breed? breedChoice = null;
            string? userInput;

            while(breedChoice == null)
            {
                Console.WriteLine();
                Console.WriteLine("Welcher Rasse gehört dein Charakter an?\n");
                Console.WriteLine("[1] Mensch");
                Console.WriteLine("[2] Troll");
                Console.WriteLine("[3] Ork");
                Console.WriteLine("[4] Elf");
                Console.WriteLine("[5] Zwerg\n");
                Console.Write("Eingabe: ");

                userInput = Console.ReadLine();
                breedChoice = SelectBreed(userInput);

                if(breedChoice == null)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Fehler: Ungültige Eingabe");
                    System.Threading.Thread.Sleep(500);
                    Console.ResetColor();
                }
            }

            return breedChoice.Value;
        }

        //Breed Eingabe auf korrektheit und nullwert überprüft

        private Breed? SelectBreed(string? userInput)
        {
            Breed? breedChoice;

            switch (userInput)
            {
                case "1":
                    breedChoice = Breed.Mensch;
                    break;
                case "2":
                    breedChoice = Breed.Troll;
                    break;
                case "3":
                    breedChoice = Breed.Ork;
                    break;
                case "4":
                    breedChoice = Breed.Elf;
                    break;
                case "5":
                    breedChoice = Breed.Zwerg;
                    break;
                default:
                    breedChoice = null;
                    break;
            }

            return breedChoice;
        }

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

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

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

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

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

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

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...