[英]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.