C#多态性问题再一次 - 重写字段?

时间:2009-04-07 17:18:33

标签: c# xna polymorphism

这次我遇到虚拟字段问题。

我的游戏对象有核心课程。此类包含具有Model类对象的字段。模型的对象包含诸如位置等的值。

现在 - 在绘图时我需要从它的模型中读取每个对象的位置。当我使用派生而不是默认模型类时,问题就开始了。例如:

abstract class GenericGameObject { public DefaultGameObjectModel Model = new DefaultGameObjectModel(); }
class Missile : GenericGameObject { public new MissileModel Model = new MissileModel(); }

class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }

Missile m = new Missile();
m.Model.Position.X = 10;
// NOT OK! ((GenericGameObject)m).Model.Position.X == 0

我尝试将模型定义为虚拟属性而不是字段,但这会失败,因为 派生属性必须与其基础类型相同。铸造是徒劳的,因为会有许多其他模型类型。如果我想从派生类中读取值而不是从base中读取值,我该怎么办?

我已经问了这个问题,但答案没有带来任何解决方案。释:

  • 使用界面IGameObjectModel

    概念很好,但我必须强制执行字段。接口无法定义字段,因此我必须定义属性。但是我不能做IGameObjectModel.Position.X = 10,因为Position不是一个字段。

  • 使GenericGameObject成为通用类型,例如GenericGameObject,Missile是从GenericGameObject派生的类型 然后我无法将导弹投射到GenericGameObject,并且通常将这些对象存储在同一列表中。当然我可以创建这两个可以继承的主要基类型,但是后来我无法访问模型字段。

  • 使模型成为属性而不是字段。 在派生类中更改属性类型是不可能的。

我可以做什么?

5 个答案:

答案 0 :(得分:2)

在这种情况下,最好的方法是将父字段的值指定为派生类的实例,然后将其强制转换为派生类或保留派生类的引用(可能更好)。

或者你可以走这条路,我最喜欢......

abstract class GenericGameObject
{
    public DefaultGameObjectModel Model
    {
        get { return ModelInternal; }
    }

    protected abstract DefaultGameObjectModel ModelInternal { get; }
}

class Missile : GenericGameObject
{
    private MissileModel model = new MissileModel();

    public override DefaultGameObjectModel ModelInternal
    {
        get { return model; }
    }

    public new MissileModel Model
    {
        get { return model; }
        set { model = value; }
    }
}

class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }

Missile m = new Missile();
m.Model.Position.X = 10;

此解决方案使您可以从基类的上下文访问基本模型实例,同时允许您从继承的类访问具体的模型实例。

答案 1 :(得分:2)

没有“虚拟领域”这样的东西。只有propertiesmethods可以是虚拟的。

在您的Missle类中,您似乎正在使用new keyword as a modifier来隐藏名为Model的继承成员。

当您以这种方式隐藏继承的成员时,您不会获得多态行为。这很糟糕,因为基类中的代码(如果它引用了Model字段)可能无法按预期工作。

最好的选择:使用房产。根据需要强制转换或概括(将成员移动到基类)。

答案 2 :(得分:1)

如果你使用了界面,我相信你仍然可以打电话:

IGameObjectModel.Position.X = 10;

只要您用于Position的对象类型具有名为X的读/写属性。您的界面将类似于:

public interface IGameObjectModel
{
    Vector2 Position
    {
        get;
        // only add set if you need to set the Position object outside of your class
        // set;
    }

    // ...other properties
}

答案 3 :(得分:1)

你说如果你使用了一个属性的接口你“不能做IGameObjectModel.Position.X = 10”。我假设这是因为Vector2是一个结构,因此具有值类型语义。如果这是正确的,您只需将Position属性分配给从原始值计算的新Vector2。例如:

Missile m = new Missile();
m.Model.Position = new Vector2()
{
    X = m.Model.Position.X + 10,
    Y = m.Model.Position.Y
};

答案 4 :(得分:0)

你尝试过使用泛型吗?使用泛型,您可以将游戏对象模型与游戏对象分开。然后,您可以使用任何游戏对象模型实例化您的游戏对象。游戏对象可以通过标准界面与游戏对象模型进行通信。

interface IGameObjectModel {
    void Shoot();
        :
}

class GameObject<TModel> where TModel:IGameObjectModel {
    public TModel Model;
    public GameObject(TModel model) {
        Model = model;
    }
    public void Shoot() {
        Model.Shoot();
    }
        :
}

class MissleModel : IGameObjectModel {
    public void Shoot() {
        :
    }   
}

通过上述内容,您可以使用missle模型实例化您的游戏对象: -

MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
    new GameObject<MissleModel>(model);