Pergunta

Estou tentando resolver isso há muito tempo (3 dias) e simplesmente não consigo descobrir.Tentarei explicar o problema de forma abrangente porque é um pouco mais complexo.

Minha tarefa escolar é criar um jogo de texto simples usando OOP em C# Visual Studio 2008 (deve ser construído em uma biblioteca que o professor nos forneceu).Deve usar apenas console.Tenho uma experiência decente com OOP de PHP e C++, mas ainda não consigo descobrir isso.

80% do jogo de texto já está funcionando então não vou te aborrecer com aulas e coisas que já funcionam e não estão relacionadas ao problema.Ok, vamos começar:

Cada comando no jogo (o que você pode digitar no console e pressionar Enter) é representado por uma única classe que estende uma classe abstrata e uma interface da biblioteca na qual devo construir o jogo.Abaixo está uma classe Use que representa um comando para usar itens (por exemplovocê digita "use espada" no console e o jogo procurará por um item chamado espada e chamará seu método de uso):

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

Existem duas outras classes que são usadas.A classe Parser e a classe Game.Falta um pouco mais, então postarei apenas trechos de coisas relevantes deles.Classe do analisador:

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

Agora, um trecho da classe Game onde estou usando as duas classes acima:

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

Adicionei comentários aos trechos para descrever onde está o problema.Espero ter explicado bem.

Alguém tem alguma ideia?Estou trabalhando nesses projetos há cerca de 3 semanas e a maior parte das coisas correu bem quando, há 3 dias, me deparei com esse problema e, desde então, tenho tentado entendê-lo.

Foi útil?

Solução

Seu problema é com a palavra -chave 'nova'. Aqui é onde você está usando na classe 'Uso':

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

Você está criando uma propriedade diferente que possui o mesmo nome de uma propriedade do tipo do qual você está herdando. A palavra -chave 'nova' diz ao compilador que você pretende fazer.

Basicamente, isso significa que, se você fizer o seguinte:

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

Você obterá esta saída:

DIRETO: ABCD

Acommand: Wxyz

Você provavelmente deseja remover a definição de 'parâmetros' inteiramente do uso e apenas herdar o da Acommand. Provavelmente do nome e descrição também, mas você poderá descobrir daqui, se quiser ou não.

Outras dicas

Sem ver o código da classe Acommand ... tente remover o operador "novo" na declaração dos parâmetros da classe de uso. Quando você está configurando a propriedade c.params = comando; está na verdade definindo a propriedade da classe base, no método executado, você está verificando.

// Isto é apenas um teste porque parece que o problema é
// com a propriedade de parâmetros.Deveria haver um comando
// você digitou no console mas é sempre nulo
// Observe que ainda não codifiquei o corpo deste método.
// Farei isso assim que resolver o problema.

Isso é causado por você declarar novidades em suas propriedades.Eles devem ser substituídos ou não incluídos se você não precisar alterar a lógica do ACommand.

Quando você faz referência como um ACommand:

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

Você usará os parâmetros do ACommand ou suas substituições (se você tiver definido uma).

Seus novos Params sombreiam os Params do ACommand e só serão acessíveis se sua referência for um UseCommand.

Seu problema está aqui:

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

No seu código:

c.Params = command;

você está referenciando o tipo TextGame.Commands.ACommand. Como você está escondendo a propriedade Param em sua subclasse, está causando uma referência não polimórfica. Remova a definição acima e confie na definição de param da classe base, e você ficará bem.

Já faz um tempo desde que encontrei esse problema, mas se você abrir isso no refletor, espero que veja que está escondendo o uso. Propriedade de params por trás de uma callvirt explicitamente ligada ao seu tipo de base ... como o mais rápido Typens apontou.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top