web-dev-qa-db-fra.com

Création d'une liste générique d'objets en C #

En guise d'introduction, je crée un moteur Quadtree de base à des fins d'apprentissage personnel. Je veux que ce moteur ait la capacité de travailler avec de nombreux types de formes différents (pour le moment, je vais avec des cercles et des carrés) qui se déplaceront tous dans une fenêtre et effectueront une sorte d'action en cas de collision.

Voici mes objets de forme tels que je les ai jusqu'à présent:

public class QShape {
    public int x { get; set; }
    public int y { get; set; }
    public string colour { get; set; }
}

public class QCircle : QShape {
    public int radius;
    public QCircle(int theRadius, int theX, int theY, string theColour) {
        this.radius = theRadius;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
}

public class QSquare : QShape {
    public int sideLength;
    public QSquare(int theSideLength, int theX, int theY, string theColour) {
        this.sideLength = theSideLength;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
}

Maintenant, ma question est, comment puis-je créer une liste générique (List<T> QObjectList = new List<T>();) en C # afin que je puisse avoir une liste contenant toutes ces différentes formes qui peuvent avoir des propriétés différentes (par exemple, QCircle a la propriété "radius" tout en QSquare a la propriété "sideLength")? Un exemple de mise en œuvre serait également utile.

Je sais juste qu'il y a une réponse stupidement évidente à cette question mais j'apprécierais quand même toute aide. J'essaie de revenir en C #; cela fait évidemment un moment ...

9
Djentleman

Vous devez utiliser le downcasting

Stockez les objets dans une liste avec la classe de base

 List<QShape> shapes = new List<QShape>

Vous pouvez ensuite convertir l'objet en toute sécurité si vous savez de quoi il s'agit, par exemple.

if(shapes[0] is QSquare)
{
     QSquare square = (QSquare)shapes[0]
} 

Vous pouvez également implicitement abattre des objets

QSquare square = new Square(5,0,0,"Blue");
QShape shape =  square

Pour plus d'informations, lisez les sections Upcasting et Downcasting ici

7
Joel

Vous devez implémenter un Interface. Par exemple

public interface IHasLength
{
    int Length;
}

Ensuite, dans la mise en œuvre, vous pouvez faire

public class QSquare : QShape, IHasLength {
    public int sideLength;
    public QSquare(int theSideLength, int theX, int theY, string theColour) {
        this.sideLength = theSideLength;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
    public int Length { get { return sideLength; } }
}
public class QCircle : QShape, IHasLength {
    public int radius;
    public QSquare(int theSideLength, int theX, int theY, string theColour) {
        this.sideLength = theSideLength;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
    public int Length { get { return radius; } }
}

Enfin, dans votre liste:

List<IHasLength> shapesWithSomeLength = new List<IHasLength>();

Maintenant, votre liste peut contenir TOUT ce qui implémente IHasLength que ce soit un QCircle, QShape, ou même un QDuck si vous voulez tant qu'il implémente IHasLength.

3
Pete

C'est ce que tu veux?

public class QShape
{
    protected QShape() { }
    public int x { get; set; }
    public int y { get; set; }
    public string colour { get; set; }
}

public class QCircle : QShape
{
    public int radius;
    public QCircle(int theRadius, int theX, int theY, string theColour)
    {
        this.radius = theRadius;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
}

public class QSquare : QShape
{
    public int sideLength;
    public QSquare(int theSideLength, int theX, int theY, string theColour)
    {
        this.sideLength = theSideLength;
        this.x = theX;
        this.y = theY;
        this.colour = theColour;
    }
}
class Program
{
    static void Main(string[] args)
    {
        List<QShape> list = new List<QShape>();
        list.Add(new QCircle(100, 50, 50, "Red"));
        list.Add(new QCircle(100, 400, 400, "Red"));
        list.Add(new QSquare(50, 300, 100, "Blue"));


        foreach (var item in list.OfType<QCircle>())
        {
            item.radius += 10;
        }

        foreach (var item in list.OfType<QSquare>())
        {
            item.sideLength += 10;
        }
    }
}
2
ja72

Vous pouvez les stocker dans un List<QShape> mais cela signifierait que vous ne pourriez pas accéder aux propriétés spécifiques au type.

Généralement, vous pouvez aborder cela en fournissant une interface commune dans votre classe de base et en remplaçant le comportement dans les sous-classes. De cette façon, une interface commune peut masquer un tas de comportements divers. Par exemple, une méthode Grow pourrait masquer la complexité des éléments en croissance de forme différente et pourrait être appelée sans connaissance explicite de la forme sur laquelle elle fonctionne.

public abstract class QShape {
    public abstract void Grow(int amt);
}
public class QSquare : QShape {
    private int sideLength;
    public override void Grow(int amt)
    {
        sideLength+=amt;
    }
}
public class QCircle : QShape {
    private int radius;
    public override void Grow(int amt)
    {
        radius+=amt;
    }
}
2
spender

J'ai l'impression de manquer quelque chose mais ...

List<QCircle> circleObjects = new List<QCircle>();

et

List<QSquare> squareObjects = new List<QSquare>();

fonctionnera parfaitement bien.

ÉDITER:

Ah, je n'ai pas compris ce qui était demandé.

Oui, comme vos classes QCircle et QSquare héritent de QShape, vous pouvez simplement le faire.

List<QShape> shapes= new List<QShape>();

Il convient de noter que si vous souhaitez accéder à la propriété radius de tous les QCircle de cette liste, vous devrez filtrer la liste en fonction du type.

1
Alastair Pitts

Vous pouvez utiliser le commentaire d'Ian Mercer List<QShape>

Et voici comment vous le rempliriez:

List<QShape> shapes = new List<QShape>();
QCircle circle = new QCircle(); 

shapes.Add(circle);

Pour le déballer:

QCircle circle = (QCircle) shapes[0];

Si vous devez appeler une méthode hors de la classe de base, pas besoin de la décompresser, utilisez-la.

1
Chris Gessler