イントロとして、私は個人的な学習目的で基本的な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;
}
}
_
今私の質問は、C#でジェネリックリスト(List<T> QObjectList = new List<T>();
)を作成する方法です。これにより、異なるプロパティを持つ可能性のあるこれらすべてのさまざまな形状を含む1つのリストを作成できます(たとえば、QCircleには "radius"プロパティがあります。 QSquareには "sideLength"プロパティがあります)?実装例も参考になります。
私はこの質問に愚かな明白な答えがあることを知っていますが、とにかくどんな助けでも感謝します。 C#に戻ろうとしています。明らかに久しぶりです...
ダウンキャストを使用する必要があります
オブジェクトを基本クラスのリストに格納します
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
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
を実装するANYTHINGを保持できます。
これは、あなたの望むことですか?
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<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;
}
}
何かが足りないように感じますが...
List<QCircle> circleObjects = new List<QCircle>();
そして
List<QSquare> squareObjects = new List<QSquare>();
完璧に動作します。
編集:
ああ、何が聞かれているのかわからなかった。
はい、QCircle
およびQSquare
クラスはQShape
を継承しているため、そのまま実行できます。
List<QShape> shapes= new List<QShape>();
リスト内のすべてのradius
のQCircle
プロパティにアクセスする場合は、タイプに基づいてリストをフィルタリングする必要があることに注意してください。
Ian Mercerのコメントを使用できますList<QShape>
そして、ここにそれを埋める方法があります:
List<QShape> shapes = new List<QShape>();
QCircle circle = new QCircle();
shapes.Add(circle);
開梱するには:
QCircle circle = (QCircle) shapes[0];
基本クラスからメソッドを呼び出す必要がある場合は、ボックスを解除する必要はなく、それを使用するだけです。