Domanda

Sto cercando di risolvere questo problema da anni (3 giorni) e non riesco proprio a capirlo. Proverò a spiegare il problema in modo completo perché è un po 'più complesso.

Il mio compito scolastico è di creare un semplice gioco di testo usando OOP in C # Visual Studio 2008 (dovrebbe essere costruito su una biblioteca che l'insegnante ci ha fornito). Dovrebbe usare solo la console. Ho una discreta esperienza con OOP di PHP e C ++ ma non riesco ancora a capirlo.

L'80% del gioco di testo funziona già, quindi non ti annoierò con lezioni e cose che già funzionano e non sono correlate al problema. Ok iniziamo:

Ogni comando nel gioco (ciò che puoi digitare nella console e premi invio) è rappresentato da una singola classe che estende sia una classe astratta che un'interfaccia della libreria su cui dovrei costruire il gioco. Bellow è un uso di classe che rappresenta un comando per l'utilizzo di oggetti (ad esempio, digiti " usa la spada " nella console e il gioco cercherà un oggetto chiamato spada e chiamerà il suo metodo di utilizzo):

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;
        }
    }
}

Esistono altre due classi utilizzate. La classe Parser e la classe Game. Ci sono un po 'più di tempo, quindi posterò solo frammenti di materiale pertinente. Classe Parser:

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;
        }
    }
}

Ora un frammento della classe Game in cui sto usando entrambe le classi precedenti:

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);
            }
        }
    }
}

Ho aggiunto commenti agli snippet per descrivere dove si trova il problema. Spero di averlo spiegato bene.

Qualcuno ha qualche idea? Lavoro a questi progetti da circa 3 settimane e la maggior parte delle cose sono andate bene senza problemi quando 3 giorni fa ho riscontrato questo problema e da allora ho cercato di risolverlo.

È stato utile?

Soluzione

Il tuo problema è con la parola chiave "nuova". Ecco dove lo stai usando nella classe "Usa":

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

Stai creando una proprietà diversa che ha lo stesso nome di una proprietà sul tipo da cui stai ereditando. La "nuova" parola chiave indica al compilatore che intendevi farlo.

Fondamentalmente, ciò significa che se fai quanto segue:

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

Otterrai questo output:

  

diretto: abcd

     

ACommand: wxyz

Probabilmente vuoi rimuovere completamente la definizione di 'Params' da Usa ed ereditare quella da ACommand. Probabilmente anche da nome e descrizione, ma dovresti essere in grado di capire da qui se lo vuoi o no.

Altri suggerimenti

Senza vedere il codice per la classe ACommand ... Prova a rimuovere il " nuovo " operatore nella dichiarazione Params della classe Use. Quando si imposta la proprietà c.Params = command; sta effettivamente impostando la proprietà della classe base, nel metodo Execute stai controllando this.parameters anziché base.Params.

  

// Questo è solo un test perché sembra che il problema sia
  // con la proprietà parametri. Dovrebbe esserci un comando
  // hai digitato la console ma è sempre null
  // Nota che non ho ancora codificato il corpo di questo metodo.
  // Lo farò una volta risolto il problema.

Questo è causato dal fatto che tu dichiari nuovo sulle tue proprietà. Dovrebbero essere sostituiti o non inclusi affatto se non è necessario modificare la logica di ACommand.

Quando fai riferimento come ACommand:

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

Utilizzerai i Params di ACommand o i tuoi override (se ne hai definito uno).

I tuoi nuovi Params shadow ACommand's Params e sono accessibili solo se il tuo riferimento è un UseCommand.

Il tuo problema è qui:

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

Nel tuo codice:

c.Params = command;

stai facendo riferimento al tipo TextGame.Commands.ACommand . Poiché stai nascondendo la proprietà Param nella sottoclasse, stai causando un riferimento non polimorfico. Rimuovi la definizione sopra e fai affidamento sulla definizione della classe base di Param, e andrà tutto bene.

È passato un po 'di tempo da quando ho riscontrato questo problema, ma se lo apri in Reflector mi aspetto che vedrai che stai nascondendo la proprietà Use.Params dietro una callvirt esplicitamente legata al suo tipo di base lì .... come hanno sottolineato i dattilografi più veloci.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top