在 C# 中创建通用对象列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11354620/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 17:31:47  来源:igfitidea点击:

Creating a generic list of objects in C#

c#listgenericsobjectquadtree

提问by Djentleman

By way of an intro, I'm creating a basic Quadtree engine for personal learning purposes. I'm wanting this engine to have the capability of working with many different types of shapes (at the moment I'm going with circles and squares) that will all move around in a window and perform some sort of action when collision occurs.

作为介绍,我正在为个人学习目的创建一个基本的 Quadtree 引擎。我希望这个引擎能够处理许多不同类型的形状(目前我将使用圆形和正方形),这些形状都将在窗口中移动并在发生碰撞时执行某种操作。

Here are my shape objects as I have them so far:

这是我目前拥有的形状对象:

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;
    }
}

Now my question is, how do I create a generic list (List<T> QObjectList = new List<T>();) in C# so I can have one list containing all these various shapes that may have different properties (e.g., QCircle has the "radius" property while QSquare has the "sideLength" property)? An example of implementation would be helpful as well.

现在我的问题是,如何List<T> QObjectList = new List<T>();在 C# 中创建一个通用列表 ( ) 以便我可以拥有一个包含所有这些可能具有不同属性的各种形状的列表(例如,QCircle 具有“radius”属性,而 QSquare 具有“sideLength”属性)?一个实施的例子也会有帮助。

I just know that there is a stupidly obvious answer to this question but I'd appreciate any help anyway. I'm trying to get back into C#; it has obviously been a while...

我只知道这个问题有一个愚蠢而明显的答案,但无论如何我都会感谢任何帮助。我正在尝试重新使用 C#;显然已经有一段时间了......

采纳答案by Joel

You need to use downcasting

你需要使用向下转换

Store the objects in a list with the base class

将对象存储在具有基类的列表中

 List<QShape> shapes = new List<QShape>

You can then upcast the object safely if you know what it is e.g.

如果您知道它是什么,那么您就可以安全地向上投射对象,例如

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

You can also implicitly downcast objects

您还可以隐式向下转换对象

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

For more information read the Upcasting and Downcasting sections here

有关更多信息,请阅读此处的向上和向下部分

回答by Alastair Pitts

I feel like i'm missing something but...

我觉得我错过了一些东西但是...

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

and

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

will work perfectly well.

将工作得很好。

EDIT:

编辑:

Ah, I didn't understand what was being asked.

啊,没看懂问的是什么。

Yes, as your QCircleand QSquareclasses inherit from QShape, you can just do.

是的,因为您的QCircleQSquare类继承自QShape,您可以这样做。

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

It's worth noting that if you want to access the radiusproperty of all the QCircle's in that list, then you are going to have to filter the list based on type.

值得注意的是,如果您想访问该列表radius中所有QCircle's的属性,那么您将不得不根据类型过滤该列表。

回答by Chris Gessler

You can use Ian Mercer's comment List<QShape>

您可以使用 Ian Mercer 的评论 List<QShape>

And here's how you would fill it:

这是你如何填写它:

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

shapes.Add(circle);

To unbox it:

拆箱:

QCircle circle = (QCircle) shapes[0];

If you need to call a method off the base class, no need to unbox, just use it.

如果需要从基类中调用方法,无需拆箱,直接使用即可。

回答by Pete

You should implement an Interface. For example

你应该实现一个Interface. 例如

public interface IHasLength
{
    int Length;
}

Then in the implementation you can do

然后在实现中你可以做

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; } }
}

FInally, in your list:

最后,在您的列表中:

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

Now your list can hold ANYTHING that implements IHasLengthwhether it's a QCircle, QShape, or even a QDuckif you want as long as it implements IHasLength.

现在,您的列表可以包含任何可以实现IHasLength的内容QCircle,无论是 a QShape、 还是 aQDuck如果您想要,只要它实现IHasLength

回答by spender

You could store them in a List<QShape>but this would mean that you could not access type-specific properties.

您可以将它们存储在 a 中,List<QShape>但这意味着您无法访问特定于类型的属性。

Generally, you might approach this by providing a common interface in your base class, and overriding behaviour in subclasses. In this way, a common interface can hide a diverse bunch of behaviours. For instance a Growmethod could hide the complexities of growing items of different shape and could be called without explicit knowlege of the shape upon which it is operating.

通常,您可以通过在基类中提供通用接口并在子类中覆盖行为来解决此问题。通过这种方式,一个通用的界面可以隐藏各种各样的行为。例如,一个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;
    }
}

回答by Jon Egeland

Storing

收藏

You're already on the right track with your class definitions. What you have to do is make a Listof the superclass (in this case, QShape), which will be able to hold all of your shapes.

您已经在类定义的正确轨道上。您需要做的是创建一个List超类(在本例中为QShape),它将能够容纳您的所有形状。

Here's an example of how you would make it:

这是一个如何制作它的示例:

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

objects.add(new QCircle(...));
objects.add(new QSquare(...));

Accessing

访问

The problem here is differentiating what is what once everything is in the list. That's done with the getType()and typeof()methods of C#. (Jon Skeet has an excellent answer about how to do this). Basically, it looks like this:

这里的问题是区分什么是什么,一旦一切都在列表中。这是通过C#的getType()typeof()方法完成的。(Jon Skeet 对如何做到这一点有一个很好的回答)。基本上,它看起来像这样:

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);

After you do this, you can resume using your objects like normal. But if you try accessing them from the list, you can only use the methods and variables that QShapehas, as every object put in the list will be cast to it.

完成此操作后,您可以像往常一样继续使用您的对象。但是,如果您尝试从列表中访问它们,则只能使用具有的方法和变量QShape,因为放入列表中的每个对象都将被强制转换为它。

回答by ja72

Is this what you want?

这是你想要的吗?

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;
        }
    }
}

回答by Bulelani Cimani

public Class abstract  Base<T>
{
    public abstract List<T>GetList();
}

then do this

然后这样做

public class className:Base<ObjectName>
{
    public override List<T>GetList()
    {
        //do work here 
    }
}