C#多态性问题再次出现-覆盖字段?
这次我遇到了虚拟字段的问题 我有我的游戏对象的核心类。此类包含具有模型类对象的字段。模型的对象包含位置等值 现在-在绘图时,我需要从模型中读取每个对象的位置。当我使用派生类而不是默认模型类时,问题就开始了。例如:C#多态性问题再次出现-覆盖字段?,c#,xna,polymorphism,C#,Xna,Polymorphism,这次我遇到了虚拟字段的问题 我有我的游戏对象的核心类。此类包含具有模型类对象的字段。模型的对象包含位置等值 现在-在绘图时,我需要从模型中读取每个对象的位置。当我使用派生类而不是默认模型类时,问题就开始了。例如: abstract class GenericGameObject { public DefaultGameObjectModel Model = new DefaultGameObjectModel(); } class Missile : GenericGameObject { pu
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
我试图将模型定义为虚拟财产而不是字段,但失败了,因为
派生属性必须与其基属性的类型相同。铸造是徒劳的,因为将有许多其他模型类型。如果我想从派生类而不是从基类读取值,我该怎么办
我已经问过这个问题了,但答案没有带来任何解决方案。解释:
- 使用接口IGameObjectModel 概念很好,但我必须强制执行字段。接口不能定义字段,所以我必须定义属性。但是我不能做IGameObjectModel.Position.X=10,因为Position不是一个字段
- 使GenericGameObject成为泛型类型,如GenericGameObject和从GenericGameObject派生的导弹类型 然后,我不能向GenericGameObject投射一枚导弹,并且通常将这些对象存储在同一个列表中。当然,我可以创建这两个可以继承的主基类型,但这样我就无法访问模型字段
- 使模型成为属性而不是字段。 无法更改派生类中的属性类型
我能做什么?如果您使用了接口,我相信您仍然可以调用:
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;
只要用于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
}
在这种情况下,最好的方法是将父字段的值指定为派生类的实例,然后将其强制转换回派生类或保留派生类的引用(可能更好) 或者你可以沿着这条路走,我最喜欢这条路
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;
此解决方案允许您从基类的上下文访问基类实例,同时允许您从继承的类访问具体的模型实例。在这种情况下,最好的方法是将父字段的值指定为派生类的实例,然后将其转换回派生类,或者保留派生类的引用(可能更好) 或者你可以沿着这条路走,我最喜欢这条路
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;
此解决方案允许您从基类的上下文访问基本模型实例,同时允许您从继承的类访问具体的模型实例。您说过,如果您使用了具有属性的接口,则“无法执行IGameObjectModel.Position.X=10”。我假设这是因为Vector2是一个结构,因此具有值类型语义。如果这是正确的,则只需将“位置”特性指定给根据原始值计算的新矢量2即可。例如:
Missile m = new Missile();
m.Model.Position = new Vector2()
{
X = m.Model.Position.X + 10,
Y = m.Model.Position.Y
};
您说过,如果您使用了一个属性为“不能执行IGameObjectModel.Position.X=10”的接口。我假设这是因为Vector2是一个结构,因此具有值类型语义。如果这是正确的,则只需将“位置”特性指定给根据原始值计算的新矢量2即可。例如:
Missile m = new Missile();
m.Model.Position = new Vector2()
{
X = m.Model.Position.X + 10,
Y = m.Model.Position.Y
};
没有所谓的“虚拟场”。只有和可以是虚拟的 在Missle类中,您似乎正在使用隐藏名为Model的继承成员 以这种方式隐藏继承成员时,不会出现多态行为。这是不好的,因为基类中的代码(如果它引用模型字段)可能无法按预期工作
最佳选择:使用属性。必要时强制转换或泛化(将成员移动到基类)。没有“虚拟字段”这样的东西。只有和可以是虚拟的 在Missle类中,您似乎正在使用隐藏名为Model的继承成员 以这种方式隐藏继承成员时,不会出现多态行为。这是不好的,因为基类中的代码(如果它引用模型字段)可能无法按预期工作
最佳选择:使用属性。必要时强制转换或泛化(将成员移动到基类)。是否尝试使用泛型?使用泛型,您可以将游戏对象模型与游戏对象分离。然后,您可以使用任何游戏对象模型实例化游戏对象。游戏对象可以通过标准接口与游戏对象模型通信
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() {
:
}
}
接口IGameObjectModel{
空射();
:
}
类GameObject,其中TModel:IGameObjectModel{
公共TModel模型;
公共游戏对象(TModel模型){
模型=模型;
}
公开射击(){
Model.Shoot();
}
:
}
类MissleModel:IGameObjectModel{
公开射击(){
:
}
}
通过上述步骤,您可以使用导弹模型实例化游戏对象:-
MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
new GameObject<MissleModel>(model);
MissleModel model=新MissleModel();
游戏对象对象=
新游戏对象(模型);
您是否尝试使用泛型?使用泛型,您可以将游戏对象模型与游戏对象分离。然后,您可以使用任何游戏对象模型实例化游戏对象。游戏对象可以通过标准接口与游戏对象模型通信
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() {
:
}
}
接口IGameObjectModel{
空射();
:
}
类GameObject,其中TModel:IGameObjectModel{
公共TModel模型;
公共游戏对象(TModel模型){
模型=模型;
}
公开射击(){
Model.Shoot();
}
:
}
Mi类