2009-05-01 7 views
5

Ho cercato di risolvere questo per anni (3 giorni) ora e non riesco proprio a capirlo. Cercherò di spiegare il problema in modo completo perché è un po 'più complesso.La proprietà è nulla, anche dopo essere stata impostata nel codice

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

L'80% del gioco di testo funziona già, quindi non mi annoierò con lezioni e materiale che funziona già e non è correlato 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 dalla libreria che dovrei costruire il gioco sopra. Bellow è una classe Usa, che rappresenta un comando per l'utilizzo di oggetti (ad esempio, si digita "l'uso della spada" nella console e il gioco verrà ricercata una spada oggetto chiamato e chiama il suo metodo 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; 
     } 
    } 
} 

ci sono due altre classi che vengono utilizzate. La classe Parser e la classe Game. Ci sono un po 'più di tempo quindi pubblicherò solo frammenti di materiale rilevante da loro. 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 dalla classe di gioco in cui sto usando entrambe le classi di cui sopra:

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 ai frammenti per descrivere il luogo dove è il problema. Spero di averlo spiegato bene.

Qualcuno ha qualche idea? Ho lavorato a questo progetto per circa 3 settimane e la maggior parte delle cose sono andate bene quando 3 giorni fa mi sono imbattuto in questo problema e da allora ho cercato di risolvere il problema.

+4

Dico che il tuo prof non merita uno schiaffo al polso per averlo sovrascritto. –

+0

Una parola sulla formattazione: grazie per aver tentato di fornire solo le informazioni pertinenti, ma anche gli esempi di codice che hai postato sono abbastanza lunghi. (Le mie linee guida: tutte le informazioni importanti dovrebbero essere contenute su un singolo schermo) Per riferimento futuro, probabilmente sarebbe stato più bello se avessi postato i campioni del codice esternamente (come su pastebin o dpaste o altro) e includessi solo i 5-10 più importanti linee nella domanda stessa. Inoltre, è davvero più facile leggere se descrivi il tuo problema nel testo della domanda, anziché (o in aggiunta a) nei commenti. –

+0

BTW - potresti prendere in considerazione la sostituzione di ArrayList con un dizionario generico. –

risposta

9

Il tuo problema è con la "nuova" parola chiave. Ecco dove è in uso il 'Usa' classe:

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

Stai creando una proprietà diversa, che guarda caso ha lo stesso nome di una proprietà del tipo che si sta ereditando da. La "nuova" parola chiave dice al compilatore che intendevi farlo.

In pratica, questo significa che se si fa la seguente:

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

Otterrete questo output:

diretta: abcd

acommand: wxyz

Probabilmente vorrai rimuovere completamente la definizione di "Params" da Use an d solo ereditare quello da ACommand. Probabilmente anche da Nome e Descrizione, ma dovresti riuscire a capire da qui se lo vuoi o no.

+0

Tu * solo * mi hai battuto :) –

+0

Grazie mille, è esattamente come l'hai descritto. Problema risolto: D Grazie signore. –

2

// Questo è solo un test, perché sembra che il problema è
// con la proprietà dei parametri.Ci dovrebbe essere un comando
// hai digitato nella console ma è sempre nullo
// Nota che non ho ancora codificato il corpo di questo metodo.
// Lo farò una volta risolto il problema.

Questo è causato dal dichiarare nuovo sulle proprietà. Questi devono essere sovrascrivibili o non inclusi affatto se non è necessario modificare la logica di ACommand.

Quando si fa riferimento come acommand:

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

Si utilizzerà sia Parametri di acommand, o le sostituzioni (se si aveva definito uno).

I tuoi nuovi Params ombreggiano i Params di ACommand e sono accessibili solo se il tuo riferimento è un UseCommand.

3

Senza visualizzare il codice per la classe ACommand ... Provare a rimuovere l'operatore "nuovo" nella dichiarazione Params della classe Use. Quando si imposta la proprietà c.Params = comando; sta in realtà impostando la proprietà della classe base, nel metodo Execute il tuo controllo this.parameters invece di base.Params.

1

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

+0

curioso perché il downvote, quando ho fornito informazioni simili, e una tecnica per esaminare il codice per confermarlo, alle risposte sopravanzate sopra. –

+0

Non ho votato, ma immagino ridondante? –

+0

Quello non ero io. Ho appena votato il tuo asnwer up. Non sono sicuro chi l'ha votato. –

2

Il tuo problema è qui:

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

Nel codice:

c.Params = command; 

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

Problemi correlati