2009-05-01 9 views
5

He estado tratando de resolver esto por edades (3 días) ahora y simplemente no puedo resolverlo. Trataré de explicar el problema exhaustivamente porque es un poco más complejo.La propiedad es nula, incluso después de haber sido configurada en el código

La asignación de mi escuela es crear un juego de texto simple usando OOP en C# Visual Studio 2008 (debe construirse en una biblioteca que el maestro nos proporcionó). Solo debería usar consola. Tengo una experiencia decente con OOP de PHP y C++, pero todavía no puedo resolver esto.

El 80% del juego de texto ya está funcionando, así que no te aburriré con clases y cosas que ya funcionan y que no están relacionadas con el problema. Ok, vamos a empezar:

Cada comando en el juego (lo que puedes escribir en la consola y presionar enter) está representado por una sola clase que extiende una clase abstracta y una interfaz de la biblioteca. Se supone que construí el juego en. Abajo es un uso de clase que representa un comando para el uso de elementos (por ejemplo, escribe "utilización espada" en la consola y el juego buscará un artículo llamado espada y llama a su 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; 
     } 
    } 
} 

hay dos otras clases que se usan. La clase Parser y la clase Game. Son un poco más largos, por lo que solo publicaré fragmentos de material relevante de ellos. analizador de clase:

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

Ahora, un fragmento de la clase Juego en el que estoy usando dos clases anteriores:

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

he añadido a los comentarios de los fragmentos para describir dónde está el problema. Espero haberlo explicado bien.

¿Alguien tiene alguna idea? He estado trabajando en estos proyectos durante aproximadamente 3 semanas y la mayoría de las cosas funcionaron sin problemas cuando hace 3 días me encontré con este problema y desde entonces he estado tratando de resolver este problema.

+4

Digo que su profesión merece una palmada en la muñeca por sobre-diseñar esto. –

+0

Una palabra sobre el formato: gracias por intentar proporcionar solo la información relevante, pero incluso las muestras de código que publicó son bastante largas. (Mi guía: toda la información importante debería caber en una sola pantalla). Para referencia futura, probablemente habría sido mejor si publicara los ejemplos de código externamente (como en pastebin o dpaste o lo que sea) y simplemente incluyera los más importantes. líneas en la pregunta en sí. Además, lo que realmente se lee más fácil si usted describe su problema en el texto de la pregunta, en lugar de (o además de) en los comentarios. –

+0

BTW: podría considerar reemplazar ese ArrayList con un Diccionario genérico. –

Respuesta

9

Tu problema es con la palabra clave "nueva". Aquí es donde se está usando en la clase de la 'utilización':

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

Estás creando una propiedad diferente que sólo pasa a tener el mismo nombre que una propiedad del tipo que está heredando de. La palabra clave 'nueva' le dice al compilador que quería hacer eso.

Básicamente, esto significa que si hace lo siguiente:

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

Usted obtendrá esta salida:

directa: abcd

acommand: WXYZ

Probablemente desee eliminar por completo la definición de 'Params' de Usar un Solo heredo el de ACommand. Probablemente también desde el Nombre y la Descripción, pero debería poder averiguarlo desde aquí si quiere o no.

+0

* solo * me ganaste :) –

+0

Muchas gracias, es exactamente como lo describiste. Problema resuelto: D Gracias señor. –

2

// Esto es sólo una prueba, ya que parece que el problema es
// con la propiedad de los parámetros.Debe haber un comando
// ha escrito en la consola pero siempre es nulo
// Tenga en cuenta que aún no he codificado el cuerpo de este método.
// Lo haré una vez que resuelva el problema.

Esto se debe a que usted declara nuevos en sus propiedades. Deben anularse o no incluirse en absoluto si no necesita cambiar la lógica de ACommand.

Cuando se hace referencia como un acommand:

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

Que va a utilizar ya sea Parámetros de acommand, o las sustituciones (si se había definido una).

Sus nuevos parámetros sombrean los parámetros de ACommand, y solo son accesibles si su referencia es UseCommand.

3

Sin ver el código para la clase ACommand ... Intente eliminar el "nuevo" operador en la declaración de Params de la clase de Uso. Cuando configura la propiedad c.Params = comando; en realidad está estableciendo la propiedad de la clase base, en el método Execute su comprobación this.parameters en lugar de base.Params.

1

Ha pasado un tiempo desde que me encontré con este problema, pero si lo abre en Reflector espero que verá que está ocultando la propiedad Use.Params detrás de una callvirt explícitamente vinculada a su tipo base allí ... . como señalaron los mecanógrafos más rápidos.

+0

curioso por qué el downvote, cuando proporcioné información similar, y una técnica para examinar el código para confirmarlo, a las respuestas arriba expuestas. –

+0

No voté, pero supongo: ¿redundancia? –

+0

Esa no era yo. Acabo de votar por tu asnwer. No estoy seguro de quién lo votó. –

2

Su problema está aquí:

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

En su código:

c.Params = command; 

está haciendo referencia al tipo TextGame.Commands.ACommand. Como está ocultando la propiedad Param en su subclase, está causando una referencia no polimórfica. Elimine la definición anterior y confíe en la definición de la clase base de Param, y estará bien.

Cuestiones relacionadas