C# - 多态性混淆重载和方法隐藏

时间:2015-07-01 16:41:24

标签: c#

我有一个名为Item的类,它充当抽象类,但未定义为一个类。该类具有MaxPerStack属性:

public class Item
{
    public short MaxPerStack
    {
        get
        {
            return this.Data.MaxPerStack;
        }
    }
}

我还有一个名为Equip的类,它派生自Item类,并且还有一个名为MaxPerStack的属性,声明为new

public class Equip : Item
{
    public new short MaxPerStack
    {
        get
        {
            return 1;
        }
    }
}

我有以下方法Add,它使用MaxPerStack的{​​{1}}属性:

item

当我这样做时:

public void Add(Item item)
{
    Console.WriteLine("Stack: {0}.", item.MaxPerStack);
}

它转到Add(new Equip()); 的{​​{1}}属性而不是MaxPerStack属性。

为什么会这样?

2 个答案:

答案 0 :(得分:5)

因为您没有将Item.MaxPerStack标记为virtual,并且您没有将Equip.MaxPerStack标记为override。你需要这两个来获得你期望的行为。

通过隐式将基本类型的方法标记为sealed并明确将派生类型标记为new,您可以防止虚拟调度,这是用于实现的确切机制确保调用基类型的方法将执行与对象的实际运行时类型关联的实现,而不是将方法静态绑定到编译时中的实现对象的类型。

答案 1 :(得分:1)

此处的问题是,您的Equip类会替换MaxPerStack类中定义的Item属性。

public class Equip : Item
{
    public new short MaxPerStack
    {
        get
        {
            return 1;
        }
    }
}

MSDN告诉您:

  

如果派生类中的方法前面带有new关键字,则该方法被定义为独立于基类中的方法。

     

...

     

使用new关键字告诉编译器您的定义隐藏了基类中包含的定义。这是默认行为。

这也适用于属性。这告诉您Equip将拥有它自己的,不相关的MaxPerStack版本。因此,当您致电Item.MaxPerStack时,您正在Item课程中访问该媒体资源,而不是Equip课程。无论您传入的Item实际上是Equip类。

要解决此问题,您可以将MaxPerStack属性设为虚拟,然后在Equip类中覆盖它。

public class Item
{
    public virtual short MaxPerStack
    {
        get
        {
            return this.Data.MaxPerStack;
        }
    }
}

public class Equip : Item
{
    public override short MaxPerStack
    {
        get
        {
            return 1;
        }
    }
}

现在,当您向Equip提供Add(Item)作为参数时,Add方法将访问MaxPerStack类的Equip属性。

MSDN告诉你:

  

如果派生类中的方法前面带有override关键字,派生类的对象将调用该方法而不是基类方法。