2009-04-07 2 views
1

Cette fois, j'ai un problème avec les champs virtuels.Question de polymorphisme C# encore une fois - champs prioritaires?

J'ai classe de base pour mes objets de jeu. Cette classe contient un champ avec un objet de classe Model. L'objet du modèle contient des valeurs telles que la position, etc.

Maintenant, en dessin, j'ai besoin de lire la position de chaque objet de son modèle. Le problème commence quand au lieu de classe de modèle par défaut j'utilise dérivé. Exemple:

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 

J'ai essayé de modèle défini comme la propriété virtuelle au lieu de champ, mais cela échoue parce que propriétés dérivées doivent être de même type que leur base. Casting est futile car il y aura beaucoup d'autres types de modèles. Que puis-je faire si je veux lire une valeur de la classe dérivée, pas de la base?

J'ai déjà posé cette question mais la réponse n'a apporté aucune solution. Explaination:

  • à utiliser l'interface IGameObjectModel

    concept est bon, mais je dois respecter les champs. Les interfaces ne peuvent pas définir de champs, je dois donc définir une propriété. Mais alors je ne peux pas faire IGameObjectModel.Position.X = 10 parce que Position n'est pas un champ.

  • pour faire GenericGameObject un type générique tel que GenericGameObject et des missiles un type dérivé de GenericGameObject Je ne pouvais alors lancer un missile à GenericGameObject et généralement stocker les objets sur la même liste. Bien sûr, je pourrais faire le type de base principal dont ces deux pourraient hériter, mais alors je n'aurais pas accès au champ Modèle.

  • pour faire du modèle une propriété au lieu du champ. Il est impossible de changer le type de propriété dans la classe dérivée.

Que pouvais-je faire?

+0

"Que puis-je faire?" - Vous pouvez commencer par éditer votre question précédente au lieu d'en poser une nouvelle. –

+0

Hm, tu as raison, je n'y ai pas réfléchi, désolé. Il semble impossible de supprimer la question pour un utilisateur non enregistré mais sûrement la prochaine fois que je modifierais celui existant. Merci :) –

+0

Il n'y a pas de "champs virtuels". Seules les propriétés ou méthodes peuvent être virtuelles. – mmmmmmmm

Répondre

2

Dans ce cas, votre meilleure approche serait d'affecter la valeur de votre champ parent d'être une instance de votre classe dérivée, puis soit le jeter à votre classe dérivée ou tenir à un référence de votre classe dérivée (probablement mieux).

Ou vous pouvez aller sur cette route, que j'aime le mieux ...

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; 

Cette solution vous donne accès à votre instance de modèle de base du contexte de la classe de base, tout en vous donnant accès à votre instance de modèle concret de la classe héritée.

+0

Et c'est une bonne réponse, merci! Je viens de vérifier cela et ça fonctionne comme il se doit! Merci encore une fois :) –

1

Si vous utilisez une interface, je crois que tu serais encore capable d'appeler:

IGameObjectModel.Position.X = 10; 

Tant que le type d'objet que vous avez utilisé pour la position a une propriété de lecture/écriture appelée X. Votre Interface serait ressembler à quelque chose comme:

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

En fait, je ne suis même pas capable d'utiliser à la fois obtenir et définir des accesseurs:/ –

+1

Cela ne fonctionnera pas. Le Vector2 de XNA est une structure, pas une classe. Vous auriez besoin d'un accesseur set, et devez définir la structure entière. –

1

Vous avez dit que si vous utilisiez une interface avec une propriété que vous "ne pouvez pas faire IGameObjectModel.Position.X = 10 "Je suppose que c'est parce que Vector2 est une structure et a donc une sémantique de type value.Si ceci est correct, vous devez simplement assigner la propriété Position à un nouveau Vector2 calculé à partir de la valeur d'origine.Par exemple:

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

Il n'y a pas une telle chose comme « champs virtuels ». Seuls properties et methods peut être virtuelle.

Dans votre classe Missle, vous semblez utiliser le new keyword as a modifier pour cacher le membre hérité du nom de modèle.

Lorsque vous cachez un membre hérité de cette manière, vous n'obtenez pas de comportement polymorphe. est incorrect car le code de votre classe de base (s'il fait référence au champ Modèle) peut ne pas fonctionner comme prévu.

Meilleur résultat: Utiliser une propriété. Diffuser ou généraliser (déplacer les membres vers la classe de base) selon les besoins.

0

Avez-vous essayé d'utiliser des génériques? En utilisant des génériques, vous pouvez séparer votre modèle d'objet de jeu de votre objet de jeu. Vous pouvez ensuite instancier votre objet de jeu avec n'importe quel modèle d'objet de jeu. L'objet de jeu peut communiquer avec le modèle d'objet de jeu via des interfaces standard.

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

Avec ce qui précède, vous pouvez instancier votre objet de jeu avec le modèle missle: -

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