【问题标题】:Accessing fields of derived classes from a List of a base class从基类列表访问派生类的字段
【发布时间】:2013-02-03 09:22:25
【问题描述】:

我正在使用 C# 和 XNA 4.0,以及 Farseer Physics Engine(与 Box2D 非常相似),并且有一个 Block 类,我从中派生出 OBlock、LBlock 等。

区块如下:

class Block
{
    public Body m_body;
    public virtual void Draw(SpriteBatch spriteBatch) { }

    public virtual void RemoveBody(World world)
    {
        //world.RemoveBody(m_body);
    }
}

我只将这些方法、字段等放入其中,以便可以在列表中访问它们的覆盖版本

所以我的覆盖版本看起来像这样: OBlock.cs

class OBlock : Block
{

    private static Texture2D blockImg; //I load this in LoadContent so I don't have loads of Texture2Ds
    public new Body m_body; //Is this right?

    public OBlock(World world, Vector2 position)
    {
        m_body = BodyFactory.CreateBody(world, position); // Create the body, changing it from null
        FixtureFactory.AttachRectangle(Game1.blockSide *2, Game1.blockSide *2, 1.0f, new Vector2(0, 0), m_body); //This bit changes between classes
        m_body.BodyType = BodyType.Dynamic;

    }

    public override void RemoveBody(World world)
    {
        world.RemoveBody(m_body);
    }

    public static void LoadImage(Texture2D tex)
    {
        OBlock.blockImg = tex;
    }

    public override void Draw(SpriteBatch spriteBatch)
    {

        Vector2 position = m_body.Position * Game1.MetreInPixels;
        Vector2 origin = new Vector2(blockImg.Width / 2, blockImg.Height / 2);

        float rotation = m_body.Rotation;

        spriteBatch.Begin();

        spriteBatch.Draw(blockImg, position, null, Color.White, rotation, origin, Game1.BLOCK_SCALE, SpriteEffects.None, 1);

        spriteBatch.End();

        base.Draw(spriteBatch);
    }
}

还有 LBlock、ZBlock 等,除了我评论的那一点之外,它们看起来都非常相似。

然后我把它们都放进去

List<Block> blocks //As a field in Game1

blocks = new List<Block>(); // In LoadContent after loading images

我想要做的是访问列表中任何 Block 的 m_body,无论使用哪种类型

blocks[index].m_body.DOSTUFF();

显然 m_body 总是为空...

【问题讨论】:

  • 当你一行一行地单步执行代码,观察对象上的 m_body 时会发生什么?

标签: c# list inheritance syntax polymorphism


【解决方案1】:

公共新身体 m_body; //这样对吗?

不!这声明了第二个存储位 - 所以你有 Block 的 m_body 和 OBlock 的 m_body 并且你只将一个初始化为非空。对 m_body 的特定引用将解析为什么的确切规则可能太无聊而不想理解。

您可能应该完全删除上面的行并花一些时间熟悉继承的基础知识,例如http://msdn.microsoft.com/en-gb/library/ms173149.aspx

【讨论】:

    【解决方案2】:
    public new Body m_body;
    

    这是不对的。 m_body 来自您的 Block 类(您应该标记为 abstract btw)在派生自它的所有类中可见。您现在正在做的事情被称为隐藏(在 imo 中应始终避免),这会导致各种并发症。

    您现在已经做到了,每个OBlock 都有两个成员m_body,一个属于Block,一个属于OBlock。这样一来,每当您在 OBlock 类中引用 this.m_body 时,您都在分配属于 OBlockm_body 字段,而仅在 Block 中声明 m_block。这是隐藏成员带来的奇怪并发症之一:

    Block myBlock = new OBlock();
    // myBlock.m_block is null, because myBlock is of type block, and remember,
    // the m_block belonging to Block is never assigned to, only the one belonging
    // to OBlock
    

    而这将按预期工作:

    OBlock myOBlock = new OBlock();
    // myOBlock.m_block isn't null, because it was assigned to in the constructor.
    

    所以避免隐藏!删除

    public new Body m_body;
    

    从你的代码文件中,你很高兴,因为在Block 中声明的m_block 无论如何都会被所有派生自它的类继承。

    【讨论】:

    • 问题是,我想要一个我可以跨步的所有不同块的列表,并访问我想要的任何块的主体。我是否正确,这需要一个基类列表来逐步执行,然后我将派生类放入其中?
    • @WilliamOsborne 您遍历列表并用派生类实例化它们中的每一个。如果您从代码中删除 public new Body m_body; 行,一切都应该没问题,并且会按照您的描述工作。
    【解决方案3】:
    public new Body m_body; 
    

    这隐藏了基类的 m_body。所以基本上你是在派生类(不是基类)中定义一个新的 m_body 实例。所以我认为这就是你的基类 m_body 为 null 的原因,因为它从未被初始化。

    所以改为删除该特定行,因为对于每个派生类,m_body 已经定义为所有派生自 Block 类。请通过this MSDN article 了解更多详情。

    【讨论】:

      猜你喜欢
      • 2015-02-25
      • 1970-01-01
      • 2021-11-28
      • 2013-08-16
      • 1970-01-01
      • 2020-07-28
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多