【问题标题】:Property is null, even after being set in code属性为空,即使在代码中设置后也是如此
【发布时间】:2010-10-23 04:54:12
【问题描述】:

我已经尝试解决这个问题已经很久(3 天)了,但我就是想不通。我会尽量全面地解释这个问题,因为它有点复杂。

我的学校任务是在 C# Visual Studio 2008 中使用 OOP 创建一个简单的文本游戏(应该建立在老师为我们提供的库上)。它应该只使用控制台。我在 PHP 和 C++ 的 OOP 方面有不错的经验,但我仍然无法弄清楚。

80% 的文字游戏已经在运行,所以我不会用已经运行但与问题无关的课程和内容让您感到厌烦。好的,让我们开始吧:

游戏中的每个命令(您可以在控制台中键入并回车)都由一个类表示,该类既扩展了抽象类,又扩展了我应该构建游戏的库中的接口。 Bellow 是一个 Use 类,它表示使用物品的命令(例如,您在控制台中输入“使用剑”,游戏将查找名为剑的物品并调用其使用方法):

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

还有另外两个使用的类。 Parser 类和 Game 类。有更长的时间,所以我只会从他们那里发布相关内容的 sn-ps。解析器类:

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

现在是 Game 类中的一个 sn-p,我正在使用上述两个类:

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

我已将 cmets 添加到 sn-ps 以描述问题出在哪里。我希望我已经解释清楚了。

有人有什么想法吗?我已经在这个项目上工作了大约 3 周,当 3 天前我遇到这个问题时,大部分工作进展顺利,从那时起我一直在努力解决这个问题。

【问题讨论】:

  • 我说你的教授因为过度设计这个而值得一记耳光。
  • 关于格式的一句话:感谢您尝试仅提供相关信息,但即使您发布的那些代码示例也有点长。 (我的指导方针:所有重要信息都应该放在一个屏幕上)为了将来参考,如果您在外部发布代码示例(例如在 pastebin 或 dpaste 或其他上)并且只包含最重要的 5-10 可能会更好问题本身的线条。此外,如果您在问题的文本中描述您的问题,而不是在 cmets 中(或除此之外),它确实会更容易阅读。
  • @Michael - 不同意。很高兴看到一些类似于 OOP 的东西,新的 vs. 覆盖障碍是在现实世界之外学习的好东西。
  • (+1) 我认为这是一个很好的 SO 作业问题的一个很好的例子。这位学生在来找我们之前显然已经对他的问题进行了长期而认真的思考,他询问了一个具体的问题,提供了代码而不仅仅是模糊的描述,并且还通过声明这是一个家庭作业问题来提供上下文。跨度>
  • @David - 是的,应该尝试将内容格式化为相关代码。但是,在这种情况下,我认为提问者不知道代码的相关部分是什么,并提供了大量代码,以便我们理解问题。我更喜欢信息太多而不是不够。

标签: c# visual-studio oop console


【解决方案1】:

您的问题与“新”关键字有关。这是您在“使用”类中使用它的地方:

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

您正在创建一个不同的属性,它恰好与您继承的类型上的属性具有相同的名称。 'new' 关键字告诉编译器你打算这样做。

基本上,这意味着如果您执行以下操作:

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

你会得到这个输出:

直接:abcd

命令:wxyz

您可能希望完全从 Use 中删除“Params”的定义,而只从 ACommand 继承该定义。可能也来自名称和描述,但如果您愿意,您应该能够从这里弄清楚。

【讨论】:

  • 非常感谢,这正是您所描述的。问题已解决:D 谢谢先生。
【解决方案2】:

// 这只是一个测试,因为看起来问题是
// 使用参数属性。应该有一个命令
// 您已在控制台中输入,但它始终为 null
// 请注意,我尚未编写此方法的主体。
// 一旦我解决了问题,我就会这样做。

这是由于您在属性上声明了新属性。如果您不需要更改 ACommand 的逻辑,这些应该被覆盖,或者根本不包括在内。

当您作为 ACommand 引用时:

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

您将使用 ACommand 的参数或覆盖(如果您已定义)。

您的新参数会影响 ACommand 的参数,并且只有当您的引用是 UseCommand 时才能访问。

【讨论】:

    【解决方案3】:

    没有看到 ACommand 类的代码...尝试删除 Use 类的 Params 声明中的“new”运算符。当您设置属性 c.Params = command;实际上是设置基类的属性,在 Execute 方法中检查 this.parameters 而不是 base.Params。

    【讨论】:

      【解决方案4】:

      自从我遇到这个问题以来已经有一段时间了,但是如果你在 Reflector 中打开它,我希望你会看到你将 Use.Params 属性隐藏在一个显式绑定到其基类型的 callvirt 后面......正如打字速度更快的人指出的那样。

      【讨论】:

      • 很好奇为什么在我提供类似信息时投反对票,以及检查代码以确认它的技术,对上面投赞成票的答案。
      • 那不是我。我刚刚投票给你的答案。不知道是谁投了反对票。
      • 我投了反对票,因为我认为期望一个被录取的新手理解你的意思是不合理的“......将 User.Params 属性隐藏在显式绑定到其基本类型的 callvirt 后面。 ..”,也不知道如何从 MSIL 中判断这一点。更不用说为此阅读 MSIL 是一种极大的浪费时间 - 语言按设计运行,他只需要理解该语言。
      【解决方案5】:

      你的问题在这里:

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

      在您的代码中:

      c.Params = command;
      

      您正在引用类型 TextGame.Commands.ACommand。因为您在子类中隐藏了 Param 属性,所以导致了非多态引用。去掉上面的定义,依赖Param的基类定义,就可以了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-11
        • 2021-08-03
        • 1970-01-01
        相关资源
        最近更新 更多