Frage

Ich habe jetzt seit Ewigkeiten (3 Tage) versucht, dies zu lösen, und ich kann es einfach nicht herausfinden. Ich werde versuchen, das Problem umfassend zu erklären, da es etwas komplexer ist.

Meine Schulaufgabe ist es, ein einfaches Textspiel mit OOP in C# Visual Studio 2008 zu erstellen (sollte auf einer Bibliothek basieren, die der Lehrer für uns bereitgestellt hat). Es sollte nur eine Konsole verwenden. Ich habe eine anständige Erfahrung mit OOP von PHP und C ++, aber ich kann das immer noch nicht herausfinden.

80% des Textspiels funktionieren bereits, so dass ich Sie nicht mit Klassen und Sachen langweilen werde, die bereits funktionieren und nicht mit dem Problem zusammenhängen. Ok, lass uns anfangen:

Jeder Befehl im Spiel (was Sie in die Konsole eingeben und Eingabetaste drücken können) wird durch eine einzelne Klasse dargestellt, die sowohl eine abstrakte Klasse als auch eine Schnittstelle aus der Bibliothek erweitert, auf die ich das Spiel erstellen soll. Bellow ist eine Klasse, die einen Befehl zur Verwendung von Elementen darstellt (z. B. tippen Sie "Sword" in die Konsole eingeben, und das Spiel sucht nach einem Element namens Sword und ruft seine Verwendungsmethode auf):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Game.Commands
{
    class Use : TextGame.Commands.ACommand, TextGame.Commands.ICommand
    {
        private string name;
        public new string Name
        {
            set { this.name = value; }
            get { return this.name; }
        }

        private string description;
        public new string Description
        {
            set { this.description = value; }
            get { return this.description; }
        }

        private string parameters;
        public new string Params
        {
            set { this.parameters = value; }
            get { return this.parameters; }
        }

        public Use(string name, string description) : base(name, description)
        {
            this.name = name;
            this.description = description;
        }

        private TextGame.Core.GameState gameState;
        public TextGame.Core.GameState Execute(TextGame.Core.IGame game)
        {
            // This is just a test because it appears the problem is
            // with the parameters property. There should be a command
            // you have typed in the console but its always null
            // Note that I have not yet coded the body of this method.
            // I will do that once I solve the problem.
            if (this.parameters == null)
            {
                Console.WriteLine("is null");
            }
            else
            {
                Console.WriteLine(this.parameters);
            }
            return this.gameState;
        }
    }
}

Es gibt zwei weitere Klassen, die verwendet werden. Die Parserklasse und die Spielklasse. Es gibt etwas länger, so dass ich nur Ausschnitte von relevanten Sachen von ihnen veröffentlichen werde. Parserklasse:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; // ArrayList, Dictionary, Hashtable
using System.Text.RegularExpressions; // regex engine
using Game.Commands;

namespace Game
{
    class Parser
    {
        private ArrayList commands = new ArrayList();

        // All commands that are available in the game so far are
        // initialized here in the constructor (and added to the arraylist)...
        // skip to the other method this is not important
        public Parser()
        {
            this.commands.Add(new North("^north", "Go north"));
            this.commands.Add(new South("^south", "Go south"));
            this.commands.Add(new East("^east", "Go east"));
            this.commands.Add(new West("^west", "Go west"));
            this.commands.Add(new Use("^use\\s\\w+", "Try to use the selected item"));
            this.commands.Add(new Quit("^quit", "Quit the game"));
        }

        // This method takes as an argument a string representing
        // a command you type in the console. It then searches the arraylist
        // via the regex. If the command exists, it returns an the command object
        // from the arraylist
        // This works fine and returns right objects (tested)
        public TextGame.Commands.ACommand GetCommand(string command)
        {
            TextGame.Commands.ACommand ret = null;
            foreach (TextGame.Commands.ACommand c in this.commands)
            {
                Regex exp = new Regex(@c.Name, RegexOptions.IgnoreCase);
                MatchCollection MatchList = exp.Matches(command);
                if (MatchList.Count > 0)
                {
                    ret = c;
                }
            }
            return ret;
        }
    }
}

Jetzt ein Ausschnitt aus der Spielklasse, in dem ich beide über Klassen verwende:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TextGame.Core;
using System.Collections;
using Game.Items;
using Game.Commands;

namespace Game
{
    class Game : TextGame.Core.IGame
    {

        public void Play()
        {   
            // Here I read commands from the console in a loop and
            // call the ProcessCommand() method. No problem here.
            while (true)
            {
                string command = Console.ReadLine();
                this.ProcessCommand(command);
            }
        }

        // This is the IMPORTANT method so take a closer look
        private TextGame.Core.GameState gameState;
        public TextGame.Core.GameState ProcessCommand(string command)
        {
            Parser parser = new Parser();
            TextGame.Commands.ACommand c = parser.GetCommand(command);
            if (c != null)
            {
                // HERE I ADD THE COMMAND FROM THE CONSOLE TO THE C OBJECT
                // I ADD IT VIA THE SETTER TO THE PARAMETERS PROPERTY
                // OF THE COMMAND
                c.Params = command;
                // AND I CALL THE COMMAND'S EXECUTE() METHOD - SEE THE FIRST CLASS -
                // USE - WHERE I TEST FOR THE PARAMS PROPERTY BUT IT IS STILL NULL
                this.gameState = ((TextGame.Commands.ICommand)c).Execute(this);
            }
        }
    }
}

Ich habe den Snippets Kommentare hinzugefügt, um zu beschreiben, wo das Problem ist. Ich hoffe ich habe es gut erklärt.

Hat jemand irgendwelche Ideen? Ich arbeite jetzt seit ungefähr 3 Wochen an diesen Projekten und das meiste lief reibungslos, als ich vor 3 Tagen auf dieses Problem gestoßen bin, und seitdem habe ich versucht, meinen Kopf um dieses Problem zu machen.

War es hilfreich?

Lösung

Ihr Problem ist mit dem Keyword "neues" Keyword. Hier verwenden Sie es in der Klasse "Verwenden":

    private string parameters;
    public new string Params
    {
        set { this.parameters = value; }
        get { return this.parameters; }
    }

Sie erstellen eine andere Eigenschaft, die zufällig denselben Namen wie eine Eigenschaft auf dem Typ hat, von dem Sie erbeln. Das 'neue' Schlüsselwort sagt dem Compiler, dass Sie das tun wollten.

Grundsätzlich bedeutet dies, dass wenn Sie Folgendes tun:

var x = new Use();
x.Params = "abcd";
((ACommand)x).Params = "wxyz";
Console.Writeline("direct: " + x.Params);
Console.Writeline("ACommand: " + ((ACommand)x).Params);

Sie erhalten diese Ausgabe:

Direkt: ABCD

Acommand: WXYZ

Sie möchten wahrscheinlich die Definition von 'Params' vollständig von der Verwendung entfernen und einfach die von Acommand erben. Wahrscheinlich auch von Namen und Beschreibung, aber Sie sollten in der Lage sein, hier herauszufinden, ob Sie dies möchten oder nicht.

Andere Tipps

Ohne den Code für die Akommand -Klasse zu sehen ... Versuchen Sie, den "neuen" Operator in der Paramserklärung der Verwendung der Verwendung zu entfernen. Wenn Sie die Eigenschaft festlegen c.params = Befehl; Setzt die Eigenschaft der Basisklasse tatsächlich in der Ausführungsmethode, um dies zu überprüfen. Parameter anstelle von Base.params.

// Dies ist nur ein Test, da es sich ansieht, dass das Problem ist
// mit der Parametereigenschaft. Es sollte einen Befehl geben
// Sie haben die Konsole eingegeben, aber es ist immer null
// Beachten Sie, dass ich den Körper dieser Methode noch nicht codiert habe.
// Ich werde das tun, sobald ich das Problem löste.

Dies wird darauf verursacht, dass Sie Ihre Eigenschaften neu erklären. Diese sollten überschrieben oder überhaupt nicht enthalten sein, wenn Sie die Logik von Acommand nicht ändern müssen.

Wenn Sie sich als Akommand beziehen:

TextGame.Commands.ACommand c = parser.GetCommand(command);            
c.Params = command;

Sie verwenden entweder die Parameter von Acommand oder Ihre Überschüsse (wenn Sie einen definiert haben).

Ihre neuen Params Shadow Acommand -Parameter und sind nur zugänglich, wenn Ihre Referenz ein UseScommand ist.

Ihr Problem ist hier:

private string parameters;
public new string Params
{
    set { this.parameters = value; }
    get { return this.parameters; }
}

In Ihrem Code:

c.Params = command;

Sie verweisen auf den Typ TextGame.Commands.ACommand. Da Sie die Parameigenschaft in Ihrer Unterklasse verstecken, verursachen Sie eine nicht polymorphe Referenz. Entfernen Sie die obige Definition und verlassen Sie sich auf die Basisklassendefinition von Param, und es wird Ihnen gut gehen.

Es ist schon eine Weile her, seit ich dieses Problem gestoßen habe, aber wenn Sie das im Reflektor öffnen, erwarte ich, dass Sie die Verwendung der Verwendung versteckt. Params Eigenschaft hinter einem Callvirt, das ausdrücklich an seinen Basistyp gebunden ist ... als schneller Schreibkräfte wiesen darauf hin.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top