Creating a generic list of objects in C# - c#

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.
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.
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...

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

You should implement an Interface. For example
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 IHasLength whether it's a QCircle, QShape, or even a QDuck if you want as long as it implements IHasLength.

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

You could store them in a List<QShape> but this would mean that you could not access type-specific properties.
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 Grow method 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.
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;
}
}

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 QCircle and QSquare classes inherit from QShape, you can just do.
List<QShape> shapes= new List<QShape>();
It's worth noting that if you want to access the radius property of all the QCircle's in that list, then you are going to have to filter the list based on type.

You can use Ian Mercer's comment 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.

Storing
You're already on the right track with your class definitions. What you have to do is make a List of the superclass (in this case, QShape), which will be able to hold all of your shapes.
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:
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 QShape has, as every object put in the list will be cast to it.

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

Related

Accessing attributes within a class and outside of a class

Main method with some tree objects:
namespace Forest
{
class Program
{
static void Main(string[] args)
{
Tree Fir = new Tree();
Fir.species = "Fir";
Fir.height = 100.0;
Fir.trunkDiameter = 10.0;
Tree Oak = new Tree();
Oak.species = "Oak";
Oak.height = 120.0;
Fir.trunkDiameter = 12.5;
}
}
}
A tree class:
namespace Forest
{
class Tree
{
public string species;
public double height;
public double trunkDiameter;
}
}
I want to add an attribute as such: public double trunkCircumference = trunkDiameter * 3.14
But when I do that, the trunkDiameter variable isn't recognized. When adding a static modifier, it fixes, but I cannot access trunkDiameter.
I would just like to add a trunkCircumference attribute.
Since trunkCircumference appears to always return trunkDiameter * 3.14, you could define it as a property, instead of a field.
namespace Forest
{
class Tree
{
public string species;
public double height;
public double trunkDiameter;
public double trunkCircumference
{
get => return trunkDiameter * 3.14;
}
}
}

How to avoid assignments of multiple arguments passed to constructor

If i have a class in c# containing many variables that needs to be initialised in a constructor e.g.
public class AnyClass
{
private int Var1;
private int Var2;
...
private int varN;
public AnyClass(int InVar1,int InVar2,...,InVarN)
{
Var1=InVar1;
Var2=InVar2;
...
VarN=InVarN;
//
//Code
//
}
}
Is there a way to avoid the intermediate variables InVar1, InVar2 etc in such a way that the arguments passed to the constructor are automatically mapped to the variables contained in the class.
Not at present, C# 6 may include it.
This is what is may look like
Before
public class Point {
private int x, y;
public Point(int x, int y)
this.x = x;
this.y = y;
}
}
After
public class Point(private int x, private int y) {
}
If you don’t mind having properties with a public setter, you can use Object initializers. E.g.
Cat cat = new Cat { Age = 10, Name = "Fluffy" };

Accessing and setting the instance variable of one class from another class

I currently have a class called:
public class HeatmapComponent : GH_Component
I also have another class called:
public class HeatMap
Inside the Heatmap class I have two instance variables declared as:
public int _width;
public int _height;
I would like to be able to access and set the _width and _height variables from the HeatmapComponent class. I know this is a scope issue, but, I am a bit confused as to what needs to be done.
In my HeatmapComponent class, this was what I had in mind:
this._width = width; // width is declared somewhere in this class
this._height = height; // height is same as above
I apologize beforehand if this is a stupid question. Please let me know if I am missing code snippets. I'll be happy to provide.
You want to set the values of those two fields? They are readonly. You can do that only in the constructor.
public class HeatMap
{
private readonly int _width;
private readonly int _height;
public HeatMap(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
And, as it is with passing things through constructor's params, you can use/provide them only when building a new instance. That's why they are called constructor and readonly fields:
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
void createMapAndDoSomething()
{
var hmap = new HeatMap(widthOfMap, heightOfMap);
hmap.thing();
}
}
If you don't want to create a new HeatMap, and if you want to be able to set the width/height from some 'external' place at any point in time, then:
they cannot be readonly
some public way of changing them must exist
For example:
public class HeatMap
{
private int _width;
private int _height;
public void SetSize(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.SetSize(widthOfMap, heightOfMap);
}
}
Or sometimes even better, use properties:
public class HeatMap
{
private int _width;
private int _height;
public int Width { set { _width = value; } }
public int Height { set { _height = value; } }
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.Width = widthOfMap;
oldMap.Height = heightOfMap;
}
}
Before I answer your question, you have one major, major issue: readonly. That means that the value of the variable cannot be changed once the object is created. By anyone. Period.
Now, you have a couple ways to do this. The first is to use properties like Snorre said. In effect, you'd get this:
public class HeatMap
{
public int Width { get; set; }
public int Height { get; set; }
}
public class HeatMapComponent
{
private HeatMap myHeatMap; // Must have a reference to the object you want to change!
public void SomeMethod()
{
myHeatMap.Width = 10;
}
}
Now, the obvious downside here is that ANYONE can change the properties of HeatMap. If for some reason you really, really want to make HeatMap's width and height editable only by the HeatMapComponent, you can make HeatMapComponent an inner class, like this:
public class HeatMap
{
private int width;
private int height;
public class HeatMapComponent
{
public HeatMap myHeatMap;
public void SomeMethod()
{
myHeatMap.width = 10;
}
}
}
however, I would strongly advise you to rethink what you're trying to do. Public inner classes are actually quite rare, in my experience, as they can violate OOP principles easily. A different application design may suit you better.
Couple of things:
readonly keyword makes anything settable only in the constructor. Example:
class XYZ
{
private readonly int x;
public XYZ()
{
x = 10; //works
}
public void SomeMethod()
{
x = 100; //does not work since it is readonly
}
}
Then there's the various access modifiers: private is only accessible in the class itself, protected is accessible in inherited classes and public is accessible anywhere. Internal is accessible within the same assembly.
public class HeatMapComponent
{
HeatMap _map;
public HeatMapComponent()
{
_map = new HeatMap();
}
public void SomeMethod()
{
_map.Width = 10; //should work if Width is public and not readonly and if _map was initialized already, ie not null
}
}
This sounds like a homework question, and the problem is you are not understanding the lesson.
Here's a way to create your HeatMap class. It contains an overload so you can either set the Width and Height in the constructor or via a Set method:
public class HeatMap {
public HeatMap() {
Width = 0;
Height = 0;
}
public HeatMap(int width, int height) {
Width = width;
Height = height;
}
public void Set(int width, int height) {
Width = width;
Height = height;
}
public int Width { get; private set; }
public int Height { get; private set; }
}
To use this in your HeatmapComponent class, you only need to create an instance of your HeatMap. Here are two ways of doing that:
public HeatmapComponent() {
}
public void Test1(int width, int height) {
var hm = new HeatMap(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
public static void Test2(int width, int height) {
var hm = new HeatMap();
hm.Set(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
Be sure you understand what is going on, though.

Accessing parameters from 'object' type in C#

I am converting a VB.Net application to C# (as well as learning C#) and I ran into a problem. One of the functions takes in an object and applies modifications to certain parameters based on what is passed. This way, one function can be used to update any control passed to it, which is working fine in VB.
The full function has a lot more logic behind it, but here is a scaled back version showing the basics:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}
The problem is that 'Top', 'Left', 'Width', 'Height', etc. are not defined, since it is using the object type.
Is there a way to keep the existing structure without having to create a separate function or definition for each possible control type?
EDIT: I am using the .Net 3.5 framework.
You can use dynamic:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
dynamic dynObject = (dynamic)objObject;
dynObject.Top = TopPadding;
dynObject.Left = LeftPadding;
dynObject.Width = WidthChange;
dynObject.Height = HeightChange;
}
Or find an interface/base class (possibly Control?) that all these types have in common and use it in method signature, instead of object.
Use a base class, like MyBaseClass that has definitions for Top, Left, Width, and Height
public class MyBaseClass
{
public int Top {get; set;}
public int Left{get; set;}
public int Width {get; set;}
public int Height {get; set;}
}
and every class that you want to pass in, should derive from that base class
public class MyDerivedClass : MyBaseClass
{
}
You will need to determine if the objects passed to the function implement the same interface or inherit from the same base class that exposes those properties. If they do then simply change the interface of the function so you accept the common interface/base class type as the parameter rather than object. If not then you are left with nasty choices.
One of the solutions here is the use of interfaces. For example if I understand your question right you could try this:
public interface IMyInterface
{
int Top { get; set;}
int Left { get; set; }
int Width { get; set; }
int Height { get; set; }
}
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
if (objObject is IMyInterface)
{
((IMyInterface)objObject).Top = TopPadding;
((IMyInterface)objObject).Left = LeftPadding;
((IMyInterface)objObject).Width = WidthChange;
((IMyInterface)objObject).Height = HeightChange;
}
}
Code is not optimized but this should do the trick :)
I would venture a guess that the object being passed is in fact a Control (assuming this is a WinForms application). You could change the method signature to specify this and see if that is in fact the case, or you could cast the object to a Control and test thoroughly (and/or add logging if the cast fails:
Changing the signature:
public void TransformObject(System.Windows.Forms.Control objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}
Downcasting internally:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
var control = objObject as System.Windows.Forms.Control;
if (control != null)
{
control.Top = TopPadding;
control.Left = LeftPadding;
control.Width = WidthChange;
control.Height = HeightChange;
}
else
{
// Turns out it isn't a control, throw an exception or Log it
}
}
Don't you define the new instance of the object before calling the method.
object obj = new object()
TransformObject(obj,5,5,5,5)
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}

Understanding Google V8's Architecture

I'm not sure I understand V8's architecture (yes, I've read its documentation).
In C# with the v8sharp wrapper I write something like this, for example:
namespace App
{
class Point
{
public Point() { }
public Point(double x, double y) {
this.X = x;
this.Y = y;
}
public double X { get; set; }
public double Y { get; set; }
}
}
static class Program
{
static void Main() {
//registering with v8sharp
V8Engine engine = V8Engine.Create();
engine.Register<App.Point>();
//execute javascript
object rtn = engine.Execute("new App.Point(10, 10);");
}
}
How would I write the same thing in Standard C++ without this wrapper?
Thanks.
If you look here: http://code.google.com/apis/v8/embed.html they have a sample that is identical to yours under "Accessing Dynamic Variables"

Categories

Resources