Вопрос полиморфизма C # еще раз - переопределение полей? - PullRequest
1 голос
/ 07 апреля 2009

На этот раз у меня проблема с виртуальными полями.

У меня есть базовый класс для моих игровых объектов. Этот класс содержит поле с объектом класса 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

Я пытался сделать Модель определяемой как виртуальное свойство вместо поля, но это не удалось, потому что производные свойства должны быть того же типа, что и их база. Кастинг бесполезен, потому что будет много других типов моделей. Что я могу сделать, если я хочу прочитать значение из производного класса, а не из базы?

Я уже задавал этот вопрос, но ответ не принес никакого решения. Explaination:

  • для использования интерфейса IGameObjectModel

    Концепция хороша, но я должен применять поля. Интерфейсы не могут определять поля, поэтому я должен определить свойство. Но тогда я не могу сделать IGameObjectModel.Position.X = 10, потому что Position не является полем.

  • , чтобы сделать GenericGameObject универсальным типом, таким как GenericGameObject и Missile тип, производный от GenericGameObject Я не мог тогда бросить ракету в GenericGameObject и вообще сохранить эти объекты в том же списке. Конечно, я мог бы создать основной базовый тип, от которого могли бы наследовать эти два, но тогда у меня не было бы доступа к полю Model.

  • , чтобы сделать модель свойством вместо поля. Невозможно изменить тип свойства в производном классе.

Что я могу сделать?

Ответы [ 5 ]

2 голосов
/ 07 апреля 2009

Нет такой вещи как «виртуальные поля». Только свойства и методы могут быть виртуальными.

В вашем классе Missle вы, похоже, используете ключевое слово new в качестве модификатора , чтобы скрыть унаследованный член с именем Model.

Когда вы таким образом скрываете унаследованный член, вы не получаете полиморфное поведение. Это плохо, потому что код в вашем базовом классе (если он ссылается на поле Model) может работать не так, как вы ожидаете.

Лучшая ставка: использовать свойство. Приведение или обобщение (перемещение членов в базовый класс) по мере необходимости.

2 голосов
/ 07 апреля 2009

В этом случае лучшим вариантом будет присвоить значение вашего родительского поля экземпляру вашего производного класса, а затем либо привести его обратно к производному классу, либо сохранить ссылку на ваш производный класс (возможно, лучше ).

Или вы могли бы пойти по этому пути, который мне нравится больше всего ...

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 голос
/ 07 апреля 2009

Вы сказали, что если вы использовали интерфейс со свойством, которое «вы не можете сделать 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
};
1 голос
/ 07 апреля 2009

Если бы вы использовали интерфейс, я думаю, вы все равно сможете звонить:

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
}
0 голосов
/ 28 июня 2009

Вы пробовали использовать дженерики? Используя дженерики, вы можете отделить модель игрового объекта от игрового объекта. Затем вы можете создать экземпляр игрового объекта с любой моделью игрового объекта. Игровой объект может взаимодействовать с моделью игрового объекта через стандартные интерфейсы.

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() {
        :
    }   
}

Используя вышеизложенное, вы можете создать экземпляр игрового объекта с моделью ракеты: -

MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
    new GameObject<MissleModel>(model);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...