2009-04-07 7 views
1

Diesmal habe ich Probleme mit virtuellen Feldern.C# Polymorphie Frage noch einmal - vorrangige Felder?

Ich habe Kernklasse für meine Spielobjekte. Diese Klasse enthält ein Feld mit dem Model-Klassenobjekt. Modell-Objekt enthält Werte wie Position usw.

Jetzt - während des Zeichnens muss ich die Position jedes Objekts aus seinem Modell lesen. Das Problem beginnt, wenn ich anstelle der Standardmodellklasse abgeleitet bin. Beispiel:

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 

Ich habe versucht, Modell definiert als virtuelles Eigentum statt Feld zu machen, aber dies nicht gelingt, weil abgeleiteten Eigenschaften von derselben Art wie ihre Basis sein. Casting ist zwecklos, weil es viele andere Modelltypen geben wird. Was kann ich tun, wenn ich einen Wert aus der abgeleiteten Klasse lesen möchte, nicht aus der Basis?

Ich habe diese Frage schon gestellt, aber die Antwort brachte keine Lösung. Explaination:

  • verwenden Schnittstelle IGameObjectModel

    Konzept ist gut, aber ich muss Felder erzwingen. Schnittstellen können keine Felder definieren, daher muss ich Eigenschaften definieren. Aber ich kann IGameObjectModel.Position.X = 10 nicht ausführen, weil Position kein Feld ist.

  • machen GenericGameObject ein generischer Typ wie GenericGameObject und Missile eine Art von GenericGameObject abgeleitet ich dann nicht eine Rakete zu GenericGameObject werfen könnte und speichern im Allgemeinen jene Objekt auf derselben Liste. Natürlich könnte ich den Hauptbasistyp festlegen, von dem diese beiden erben könnten, aber dann hätte ich keinen Zugriff auf das Modellfeld.

  • um Modell eine Eigenschaft anstelle von Feld zu machen. Es ist nicht möglich, den Eigenschaftstyp in der abgeleiteten Klasse zu ändern.

Was kann ich tun?

+0

„Was kann ich tun?“ - Sie können mit der Bearbeitung Ihrer vorherigen Frage beginnen, anstatt eine neue Frage zu stellen. –

+0

Hm, du hast Recht, ich habe nicht darüber nachgedacht, sorry. Es scheint unmöglich zu sein, die Frage für den nicht registrierten Benutzer zu löschen, aber sicher würde ich das nächste Mal das bestehende bearbeiten. Danke :) –

+0

Es gibt keine "virtuellen Felder". Nur Eigenschaften oder Methoden können virtuell sein. – mmmmmmmm

Antwort

2

In diesem Fall Ihre beste Ansatz wäre, den Wert Ihrer Mutter Feld zuweisen eine Instanz der abgeleiteten Klasse zu sein, dann entweder werfen es zurück zu Ihrer abgeleiteten Klasse oder halten sie sich an eine Referenz Ihrer abgeleiteten Klasse (wahrscheinlich besser).

Oder Sie diesen Weg gehen könnte, was ich am besten gefällt ...

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; 

Diese Lösung, die Sie aus dem Kontext der Basisklasse Sie zugreifen, während die Zugriff auf Ihre Basismodell Instanz gibt zu Ihre konkrete Modellinstanz aus der geerbten Klasse.

+0

Und das ist eine gute Antwort, danke! Ich habe es gerade überprüft und es funktioniert genauso wie es sollte! Nochmals vielen Dank :) –

1

Wenn Sie eine Schnittstelle verwendet, glaube ich Sie noch in der Lage sein würden zu nennen:

IGameObjectModel.Position.X = 10; 

Solange der Objekttyp Sie für Position hat eine Lese verwendet/Schreib-Eigenschaft Ihre Schnittstelle namens X. würde in etwa so aussehen:

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

Tatsächlich bin ich nicht in der Lage, sogar beide zu verwenden, und setzen Sie Zugriffsmethoden:/ –

+1

Dies wird nicht funktionieren. XNAs Vector2 ist eine Struktur, keine Klasse. Sie benötigen einen Set-Accessor und müssen die gesamte Struktur festlegen. –

1

Sie haben gesagt, dass Sie "IGameObjectModel.Position" nicht ausführen können, wenn Sie eine Schnittstelle mit einer Eigenschaft verwendet haben.X = 10 ". Ich nehme an, dies liegt daran, dass Vector2 eine Struktur ist und daher eine Werttyp-Semantik hat. Wenn dies korrekt ist, sollten Sie die Position-Eigenschaft einfach einem neuen Vector2 zuweisen, der aus dem ursprünglichen Wert berechnet wird. Beispiel:

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

Es gibt nicht so etwas wie ‚virtuelle Felder‘. Nur properties und methods können virtuell sein.

In Ihrem Missile-Klasse, erscheinen Sie die new keyword as a modifier verwenden, um die geerbte Member zu verbergen namens Modell.

Wenn Sie ein geerbtes Element auf diese Weise ausblenden, erhalten Sie kein polymorphes Verhalten ist schlecht, weil der Code in Ihrer Basisklasse (wenn er auf das Modellfeld verweist) möglicherweise nicht wie erwartet funktioniert.

Beste Wette: Verwenden Sie eine Eigenschaft. Cast oder Generalisieren (Mitglieder in die Basisklasse verschieben) nach Bedarf.

0

Haben Sie versucht, Generika zu verwenden? Mit Generics können Sie Ihr Spielobjektmodell von Ihrem Spielobjekt trennen. Sie können dann Ihr Spielobjekt mit einem beliebigen Spielobjektmodell instanziieren. Das Spielobjekt kann mit dem Spielobjektmodell über Standardschnittstellen kommunizieren.

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

Mit dem oben können Sie dann Ihr Spiel-Objekt mit dem Modell missle instanziiert: -

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