Создание общего списка объектов в C#
в качестве вступления я создаю базовый движок Quadtree для личных учебных целей. Я хочу, чтобы этот двигатель имел возможность работать со многими различными типами фигур (на данный момент я собираюсь с кругами и квадратами), которые будут перемещаться в окне и выполнять какие-то действия при столкновении.
вот мои фигуры, а я их до сих пор:
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;
}
}
теперь мой вопрос: Как создать общий список (List<T> QObjectList = new List<T>();
) в C# поэтому я могу иметь один список, содержащий все эти различные формы, которые могут иметь разные свойства (например, QCircle имеет свойство "radius", а QSquare-свойство "sideLength")? Был бы также полезен пример осуществления.
Я просто знаю, что есть глупо очевидный ответ на этот вопрос, но я был бы признателен за любую помощь в любом случае. Я пытаюсь вернуться в C#; очевидно, прошло некоторое время...
8 ответов
вам нужно использовать downcasting
хранить объекты в списке с базовым классом
List<QShape> shapes = new List<QShape>
затем вы можете безопасно поднять объект, если знаете, что это, например
if(shapes[0] is QSquare)
{
QSquare square = (QSquare)shapes[0]
}
вы также можете неявно опускать объекты
QSquare square = new Square(5,0,0,"Blue");
QShape shape = square
для получения дополнительной информации прочитайте разделы Upcasting и Downcasting здесь
вы должны реализовать Interface
. Например
public interface IHasLength
{
int Length;
}
затем в реализации вы можете сделать
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; } }
}
наконец, в вашем списке:
List<IHasLength> shapesWithSomeLength = new List<IHasLength>();
теперь ваш список может содержать все, что реализует IHasLength
ли QCircle
, QShape
, или даже QDuck
если вы хотите, пока он реализует IHasLength
.
вы можете хранить их в List<QShape>
но это означало бы, что вы не можете получить доступ к свойствам конкретного типа.
как правило, вы можете подойти к этому, предоставив общий интерфейс в базовом классе и переопределив поведение в подклассах. Таким образом, общий интерфейс может скрывать различные типы поведения. Например,Grow
метод может скрывать сложности выращивания элементов различной формы и может быть вызван без явного знания формы, на которой он работает.
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;
}
}
это то, что вы хотите?
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;
}
}
}
Я чувствую, что мне чего-то не хватает, но...
List<QCircle> circleObjects = new List<QCircle>();
и
List<QSquare> squareObjects = new List<QSquare>();
будет прекрасно работать.
EDIT:
Ах, я не понял, о чем спрашивали.
да, как ваш QCircle
и QSquare
классы наследуют от QShape
, вы можете просто сделать.
List<QShape> shapes= new List<QShape>();
стоит отметить, что если вы хотите получить доступ к radius
свойство всех QCircle
в этом списке, то вам придется фильтровать список в зависимости от типа.
вы можете использовать комментарий Яна Мерсера List<QShape>
и вот как бы вы его заполнили:
List<QShape> shapes = new List<QShape>();
QCircle circle = new QCircle();
shapes.Add(circle);
чтобы распаковать его:
QCircle circle = (QCircle) shapes[0];
Если вам нужно вызвать метод из базового класса, нет необходимости распаковывать, просто используйте его.
хранение
вы уже на правильном пути с определения классов. Что вам нужно сделать, это сделать List
суперкласса (в данном случае, QShape
), который сможет удерживать все ваши фигуры.
вот пример того, как вы это сделаете:
List<QShape> objects = new List<QShape>();
objects.add(new QCircle(...));
objects.add(new QSquare(...));
ссылке
проблема здесь заключается в дифференциации того, что есть то, что когда-то все в списке. Это сделано с getType()
и typeof()
методы C#. (Джон У скита есть отличный ответ о том, как это сделать). В принципе, это выглядит так:
if(objects.get(some_position).getType() == typeof(QCircle))
QCircle circle = objects.get(some_position);
else if(/* like above with QSquare */)
QSquare square = objects.get(some_position);
после этого вы можете возобновить использование ваших объектов, как обычно. Но если вы попытаетесь получить к ним доступ из списка, вы можете использовать только методы и переменные, которые QShape
имеет, так как каждый объект, помещенный в список, будет приведен к нему.
public Class abstract Base<T>
{
public abstract List<T>GetList();
}
после этого
public class className:Base<ObjectName>
{
public override List<T>GetList()
{
//do work here
}
}