繁体   English   中英

C#多态性再次提出问题-覆盖字段?

[英]C# polymorphism question once again - overriding fields?

这次我对虚拟字段有疑问。

我的游戏对象有核心课程。 此类包含带有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

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

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

  • 使用接口IGameObjectModel

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

  • 为了使GenericGameObject成为通用类型,例如GenericGameObject,而Missile成为从GenericGameObject派生的类型,我便无法将导弹投掷到GenericGameObject上,并且通常将这些对象存储在同一列表中。 当然,我可以使这两个类可以继承的主要基本类型,但是那样我就无法访问Model字段。

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

我能做什么?

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

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

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;

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

没有所谓的“虚拟领域”。 只有属性方法可以是虚拟的。

在Missle类中,您似乎正在使用new关键字作为修饰符来隐藏名为Model的继承成员。

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

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

如果您使用了界面,我相信您仍然可以调用:

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
}

您说过,如果您使用带有属性的接口,则该属性“无法执行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
};

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM