Question

J'essaie de résoudre ce problème depuis très longtemps (3 jours) et je n'arrive pas à comprendre. Je vais essayer d’expliquer le problème de manière globale car c’est un peu plus complexe.

Mon travail scolaire consiste à créer un jeu de texte simple en utilisant la POO dans C # Visual Studio 2008 (doit être construit sur une bibliothèque fournie par l'enseignant). Il ne devrait utiliser que la console. J'ai une bonne expérience de la programmation orientée objet depuis PHP et C ++, mais je n'arrive toujours pas à comprendre cela.

80% du jeu de texte fonctionne déjà, donc je ne vous ennuierai pas avec des cours et des choses qui fonctionnent déjà et qui ne sont pas liées au problème. Ok commençons:

Chaque commande du jeu (ce que vous pouvez taper dans la console et appuyer sur Entrée) est représentée par une classe unique qui étend une classe abstraite et une interface de la bibliothèque sur laquelle je suis censé avoir construit le jeu. Bellow est une classe Use qui représente une commande pour utiliser des éléments (par exemple, vous tapez "utiliser un épée" dans la console et le jeu recherchera un élément appelé épée et appellera sa méthode d'utilisation):

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

Deux autres classes sont utilisées. La classe Parser et la classe Game. Il y a un peu plus longtemps, je ne posterai donc que des extraits d'extraits pertinents. Classe d'analyse:

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

Maintenant, un extrait de la classe Game où j'utilise les deux classes ci-dessus:

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

J'ai ajouté des commentaires aux extraits pour décrire où se situe le problème. J'espère que je l'ai bien expliqué.

Quelqu'un a des idées? Je travaille sur ces projets depuis environ 3 semaines maintenant et la plupart des choses se sont déroulées sans heurts lorsque j’ai rencontré ce problème il ya 3 jours. Depuis lors, j’essaie de comprendre ce problème.

Était-ce utile?

La solution

Votre problème concerne le mot clé "nouveau". Voici où vous l'utilisez dans la classe 'Use':

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

Vous créez une propriété différente qui porte le même nom qu'une propriété du type dont vous héritez. Le mot-clé "nouveau" indique au compilateur que vous voulez faire cela.

En gros, cela signifie que si vous procédez comme suit:

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

Vous obtiendrez cette sortie:

  

direct: abcd

     

ACommand: wxyz

Vous voudrez probablement supprimer la définition de 'Params' entièrement de Use et hériter de celle d’ACommand. Probablement de Nom et Description aussi, mais vous devriez pouvoir déterminer d'ici si vous le souhaitez ou non.

Autres conseils

Sans voir le code de la classe ACommand ... Essayez de supprimer le " nouveau " opérateur dans la déclaration Params de la classe Use. Lorsque vous définissez la propriété c.Params = commande; définit en fait la propriété de la classe de base, dans la méthode Execute votre vérification de this.parameters au lieu de base.Params.

  

// Ceci est juste un test car il apparaît que le problème est
  // avec la propriété parameters. Il devrait y avoir une commande
  // vous avez tapé dans la console mais sa valeur est toujours nulle
  // Notez que je n'ai pas encore codé le corps de cette méthode.
  // Je le ferai une fois le problème résolu.

Ceci est dû au fait que vous déclarez nouveau sur vos propriétés. Celles-ci doivent être écrasées ou ne pas être incluses du tout si vous n’avez pas besoin de changer la logique d’ACommand.

Lorsque vous faites référence à une ACommand:

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

Vous utiliserez soit les paramètres de ACommand, soit vos remplacements (si vous en avez défini un).

Vos nouveaux paramètres Params shadow ACommand, et ne sont accessibles que si votre référence est une UseCommand.

Votre problème est ici:

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

Dans votre code:

c.Params = command;

vous référencez le type TextGame.Commands.ACommand . Comme vous masquez la propriété Param dans votre sous-classe, vous créez une référence non polymorphe. Supprimez la définition ci-dessus et utilisez la définition de la classe de base Param, et tout ira bien.

Cela fait longtemps que je n’ai pas rencontré ce problème, mais si vous l’ouvrez dans Reflector, vous vous apercevrez que vous cachez la propriété Use.Params derrière un callvirt explicitement lié à son type de base .... comme le signalaient les dactylographes les plus rapides.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top