FridgeMagnet
FridgeMagnet

Reputation: 105

C# Enumerating Object foreach

I have a simplified version of what I want to do below. I have a class Planet which is used by the class SolarSystem. I want to use a foreach loop to write the orbitTimeInDays for each Planet in SolarSystem.

Error CS1579 foreach statement cannot operate on variables of type 'TestEnum.SolarSystem' because 'TestEnum.SolarSystem' does not contain a public definition for 'GetEnumerator'

The problem is enumeration, I've read several articles and questions about making objects Enumerable, but I can't seem to work out how to apply it to SolarSystem so I can check each Planet it's constructed from. (Eventually it will contain asteroids, etc as well, so it's not just 8 planets and Pluto.)

Can someone please help me make sense of how to Enumerate SolarSystem.

class Program
{
    static void Main(string[] args)
    {
        SolarSystem solarSystem = new SolarSystem();
        solarSystem.mercury.orbitTimeInDays = 88;
        solarSystem.venus.orbitTimeInDays = 225;
        // etc...

        foreach (Planet planet in solarSystem)
        {
            Console.WriteLine("Time taken to orbit sun (in days) : " + planet.orbitTimeInDays.ToString());
        }
    }
}

public class Planet 
{
    public double distanceFromEarth { get; set; }
    public int orbitTimeInDays { get; set; }
    // etc...

    public Planet() { }
}

public class SolarSystem 
{ 
    public Planet mercury { get; set; }
    public Planet venus { get; set; }
    // etc...

    public SolarSystem()
    {
        mercury = new Planet();
        venus = new Planet();
        // etc...
    }
}

Upvotes: 0

Views: 909

Answers (4)

GolezTrol
GolezTrol

Reputation: 116100

You cannot just enumerate all properties. Maybe the best solution would be to give SolarSystem a List or a Dictionary of planets, so you could get something like this:

public class SolarSystem 
{ 
    public Dictionary<string, Planet> Planets { get; } = new Dictionary<string, Planet>();

    public SolarSystem()
    {
        Planets.add('Mercury', new Planet());
        Planets.add('Venus', new Planet());
        // etc...
    }
}

And then enumerate like this:

foreach (Planet planet in solarSystem.Planets.Values)

A dictionary allows you to quickly find a planet by name, but if you don't require that, you could use a List instead, which just contains the values (the planets) without the name as a key. You could make the name a property of Planet instead. And even if you would need to find a planet, a simple loop to find it is also good. After all, you're not going to have thousands of planets in the solar system, so there is no big need for Dictionary's faster searching mechanism.

An advantage of a List is that it retains the order in which you add the elements. Dictonary doesn't, although there is also OrderedDictionary in case you would need both features.

Anyway, using such a collection class, whichever best fits your needs, saves you from having to implement the GetEnumerator (from the IEnumerable interface) yourself.

Upvotes: 2

Krtti
Krtti

Reputation: 62

You are creating objects for each planet. foreach will work only on collection. Better create List planetList = new List();

and add planets it to planetList and apply foreach.

Upvotes: 0

Jeroen van Langen
Jeroen van Langen

Reputation: 22038

This is not possible like the way you are doing it. Instead of creating induvidual properties for planets, you could create a list/array of planets. This way you are able to create new planets from outside the solorsystem. ;-)

Something like:

public class Planet 
{
    public double distanceFromEarth { get; set; }
    public int orbitTimeInDays { get; set; }
    public string name {get; set;}
    // etc...

    public Planet() { }
}

public class SolarSystem 
{ 
    public List<Planet> planets {get; private set;}

    public SolarSystem()
    {
        planets = new List<Planet>();
        planets.Add( new Planet { name = "mercury", distanceFromEarth = 23456 });
        planets.Add( new Planet { name = "venus", distanceFromEarth = 12456 });
    }
}

static void Main(string[] args)
{
    SolarSystem solarSystem = new SolarSystem();

    foreach (Planet planet in solarSystem.planets)
    {
        Console.WriteLine("Time taken to orbit sun (in days) : " + planet.orbitTimeInDays.ToString());
    }
}

Upvotes: 0

Patrick Hofman
Patrick Hofman

Reputation: 156948

Your solar system doesn't tell it can iterate over anything. You have to implement IEnumerable to tell the compiler that:

public class SolarSystem : IEnumerable<Planet>
{
    public IEnumerator<Planet> GetEnumerator()
    {
        yield return mercury;
        yield return venus;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

This is a basic implementation of an enumerable. It uses the yield keyword to generate an enumerator for you on the fly.

Optionally, you could create a property Planets in your class, probably something like this:

List<Planet> Planets {get;} = List<Planet>();

Then you can iterate over solarSystem.Planets.

Upvotes: 5

Related Questions