How to store different objects in one list

I have two Arc class classes and a Line class

public class Arc { protected double startx; protected double starty; protected double endx; protected double endy; protected double radius; public Arc(){} } public class Line { protected double startx; protected double starty; protected double endx; protected double endy; protected double length; public Line(){} } 

But I want to keep arcs and rows in the same list, so I tried an interface like this

 public interface Entity { double StartX(); double StratY(); double EndX(); double EndY(); } 

Then I added the appropriate methods for each class and added code to use the interface. Now I can add both types of objects to the list, but I want to get the length from the line object and do not want to add the length method to the arc or interface. Is my only way to return a line object back to a line object like this?

 List<Entity> entities = new List<Entity>(); entities.Add(new Line(10,10,5,5)); Line myLine = (Line)Entities[0] double length = myLine.Length(); 

* Assuming that I have all the correct methods in a string class.
Or is there a better / different way to do this?

+4
source share
6 answers

Or is there a better / great way to do this?

If your objects are omitted from the general class, you can save them in one collection. To do something useful with your objects without throwing away type safety, you will need to use a template:

 public interface EntityVisitor { void Visit(Arc arc); void Visit(Line line); } public abstract class Entity { public abstract void Accept(EntityVisitor visitor); } public class Arc : Entity { protected double startx; protected double starty; protected double endx; protected double endy; protected double radius; public override void Accept(EntityVisitor visitor) { visitor.Visit(this); } } public class Line : Entity { protected double startx; protected double starty; protected double endx; protected double endy; protected double length; public override void Accept(EntityVisitor visitor) { visitor.Visit(this); } } 

After that, you create an instance of EntityVisitor whenever you need to do something useful with your list:

 class EntityTypeCounter : EntityVisitor { public int TotalLines { get; private set; } public int TotalArcs { get; private set; } #region EntityVisitor Members public void Visit(Arc arc) { TotalArcs++; } public void Visit(Line line) { TotalLines++; } #endregion } class Program { static void Main(string[] args) { Entity[] entities = new Entity[] { new Arc(), new Line(), new Arc(), new Arc(), new Line() }; EntityTypeCounter counter = entities.Aggregate( new EntityTypeCounter(), (acc, item) => { item.Accept(acc); return acc; }); Console.WriteLine("TotalLines: {0}", counter.TotalLines); Console.WriteLine("TotalArcs: {0}", counter.TotalArcs); } } 

And for what it's worth, if you open up for new languages, then F # marked unions + pattern matching are a convenient alternative to the visitor pattern .

0
source

If you are in .NET 3.5 or higher, you can make this a little less ugly this way:

 List<Entity> entities = new List<Entity>(); // add some lines and some arcs var lines = entities.OfType<Line>(); 

Then you just look at the lines , which will contain all the lines (strongly typed as lines) and nothing else.

I am not saying that this is the best approach; I just say that this is one way to do what you do. I agree with Shmoopty that this is an architecture issue.

+3
source

Since Arc and Line exchange data (startx and some other fields), I suggest using a common abstract class as a parent rather than an interface. For example, Figure .

Casting is fine, although I would recommend:

 Line myLine = Entities[0] as Line; 

It will return null if Entities[0] cannot be converted to Line , and does not throw an exception. You can check if myLine does not matter after that.

+2
source

Yes, this is the only way, considering your limitations.

I would suggest adding length to the interface (since the length of the arc has a length).

The formula can be found here .

Or, alternatively, you can add a method to the interface and make it throw a NotImplementedException.

+1
source

Ask the interface to implement the "Size" property (or call it "magnitue" or "Range").

This displays the radius of the arc and the length of the lines.

Then you can get Entity.Size.

+1
source

It depends on how you want to treat the arcs when you remove them from the list. If you try to apply Arc to a line, you will get a runtime error, so for starters you have to check if the object you are working with is a string.

One way to handle arcs is to use a null object pattern. It might make sense to add a length method to Arc, which returns 0. Thus, the code that extracts the objects from the list does not have to worry about what type it is.

0
source

All Articles