2009-05-01 10 views
5

私はこれを年齢(3日間)で解決しようとしてきましたが、私はそれを理解できません。もう少し複雑なので、私は問題を包括的に説明しようとします。コードに設定してもプロパティがnullになっています

私の学校での割り当ては、C#Visual Studio 2008(教師が私たちのために提供したライブラリをベースに構築する必要があります)でOOPを使用して簡単なテキストゲームを作成することです。コンソールのみを使用してください。私はPHPとC + +からOOPのまともな経験を持っていますが、私はまだこれを理解することはできません。

テキストゲームの80%がすでに動作していますので、既に動作しているクラスとその問題に関連していないものであなたを退屈させません。さあ、始めましょう:

ゲーム内の各コマンド(コンソールに入力してEnterキーを押すことができます)は、抽象クラスとインターフェイスを継承する単一のクラスで表され、ゲームを構築するはずですに。ベローは、(あなたがコンソールに「剣を使う」とゲームは剣と呼ばれるアイテムを探して、その使用メソッドを呼び出します入力など)のアイテムを使用するためのコマンドを表すクラスを使用することである:

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

2があります。使用される他のクラス。 ParserクラスとGameクラス。もう少し時間がかかりますので、関連するもののスニペットを投稿します。 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; 
     } 
    } 
} 

私は上記のクラスの両方を使用しているゲームのクラスからの抜粋:私は、問題がどこにあるかを説明するスニペットにコメントを追加した

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

。私はそれをうまく説明したかったと思う。

誰にでもアイデアはありますか?私はこのプロジェクトを約3週間続けてきました.3日前にこの問題に遭遇し、その後この問題を回避しようとしていたとき、ほとんどのものはスムーズに進みました。

+4

私はあなたの専門家が、これを過剰に設計するために手首に叩かれていると言います。 –

+0

フォーマットに関する単語:関連情報のみを提供しようとしてくれてありがとうございますが、あなたが投稿したコードサンプルさえも長いです。 (私のガイドライン:すべての重要な情報は1つの画面に収まるはずです)将来の参考として、コードサンプルを外部に貼り付けた場合(pastebinやdpasteなどのように)、最も重要な5-10問題そのものの行また、コメントの代わりに(またはそれに加えて)質問のテキストに問題を記述すると、実際には読みやすくなります。 –

+0

BTW - そのArrayListを汎用ディクショナリに置き換えることをお勧めします。 –

答えて

9

問題は「新しい」キーワードです。あなたが「使用する」クラスでそれを使用しているのはここです:

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

あなたはちょうどあなたが継承されているタイプのプロパティと同じ名前を持つように起こるさまざまなプロパティを作成しています。 'new'キーワードは、あなたがそれを行うことを意味するコンパイラに指示します。

基本的に、これはあなたが次の操作を行う場合のことを意味します

ダイレクト:ABCD

aCommandは:WXYZ

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

をあなたはこの出力を取得します

「Params」の定義を「Use」から完全に削除することをお勧めしますdはACommandから1つだけ継承します。おそらく名前と説明からもそうですが、あなたが望むかどうかここから理解できるはずです。

+0

あなたはちょうどそれに私を打つ:) –

+0

ありがとう、まさにあなたが記述した方法です。問題が解決しました:D ありがとうございます。 –

2

//これは問題がパラメータのプロパティ
//であると思われるため、テストに過ぎません。
//コンソールに入力しましたが、常にnullです
//このメソッドの本体はまだコーディングされていないことに注意してください。
//問題を解決したらそれを行います。

これは、プロパティでnewを宣言することによって発生します。これらは、ACommandのロジックを変更する必要がない場合は、オーバーライドする必要があります。

あなたはaCommandはとして参照:

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

(あなたは1を定義していた場合)あなたがaCommandはのパラメータ、またはあなたの上書きのいずれかを使用します。

あなたの新しいParamsはACommandのParamsをシャドーし、参照がUseCommandの場合にのみアクセス可能です。

3

ACommandクラスのコードが表示されていない... UseクラスのParams宣言で "new"演算子を削除してみてください。プロパティを設定すると、c.Params = command; Executeメソッドでbase.Paramsの代わりにthis.parametersをチェックすることで、基本クラスのプロパティを実際に設定しています。

1

私はこの問題に遭遇してからしばらくしていましたが、リフレクターでそれを開くと、そこにベースタイプに明示的にバインドされたcallvirtの後ろにUse.Paramsプロパティが隠れていることがわかります。より速いタイポイストが指摘するように。

+0

好奇心が強い理由なぜ私が似たような情報を提供したのか、それを確認するためのコードを調べるテクニックを使って、上記のアップアップされた答えに興味があります。 –

+0

私は投票しませんでしたが、私は推測します - 冗長性? –

+0

それは私ではありませんでした。私はちょうどあなたの恩人に投票しました。誰がそれを否定したのか分からない。 –

2

あなたの問題はここにある:あなたのコードで

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

c.Params = command; 

あなたがタイプTextGame.Commands.ACommandを参照しています。あなたのサブクラスにParamプロパティが隠れているので、非多態的な参照が発生しています。上記の定義を削除し、Paramの基本クラス定義に頼ると、うまくいくでしょう。

関連する問題