2016-06-13 3 views
0

У меня есть упрощенная версия того, что я хочу сделать ниже. У меня есть класс Planet, который используется классом SolarSystem. Я хочу использовать цикл foreach для записи orbitTimeInDays для каждой планеты в SolarSystem.C# Перечислимый объект foreach

Ошибка CS1579 оператор Еогеасп не может работать с переменными типа «TestEnum.SolarSystem» потому что «TestEnum.SolarSystem» не содержит публичное определение «GetEnumerator»

Проблема является перечисление, Я прочитал несколько статей и вопросов о создании объектов Enumerable, но я не могу понять, как применить его к SolarSystem, чтобы я мог проверять каждую Планету, из которой она построена. (В конце концов, он будет содержать астероиды и т. Д., Так что это не только 8 планет и Плутон.)

Может кто-то, пожалуйста, помогите мне понять, как перечислить 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... 
    } 
} 
+2

Проблема заключается в том, что ваши планеты - это каждое отдельное свойство того же класса, вы можете сделать это, используя немного фантазии, но, в реальности, вам будет лучше со списком планет в вашей solarsystem .. возможно, некоторые другие реквизиты, то вы можете просмотреть список планет .. – BugFinder

+0

Цикл ForEach работает на массивах и т. д., подобно циклу 'for'. Вместо этого у вас есть один класс с несколькими свойствами. –

ответ

5

Ваша солнечная система не говорит, что она может перебирать что-либо. Вы должны реализовать IEnumerable, чтобы сообщить компилятору, что:

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

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

Это базовая реализация перечислимого. Он использует ключевое слово yield для генерации перечислителя для вас на лету.

При желании, вы можете создать свойство Planets в своем классе, наверное, что-то вроде этого:

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

Затем вы можете итерацию над solarSystem.Planets.

+0

Огромное вам спасибо, это было именно то, что мне нужно. – FridgeMagnet

0

Это невозможно, как вы это делаете. Вместо создания невидимых свойств для планет вы можете создать список/массив планет. Таким образом, вы можете создавать новые планеты извне системы solorsystem. ;-)

Что-то вроде:

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()); 
    } 
} 
2

Вы не можете просто перечислить все свойства. Возможно, лучшим решением было бы дать SolarSystem список или словарь планет, так что вы могли бы получить что-то вроде этого:

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

А затем перечислить так:

foreach (Planet planet in solarSystem.Planets.Values) 

Словарь позволяет быстро найти планету по имени, но если вы этого не требуете, вместо этого вы можете использовать список, который просто содержит значения (планеты) без имени в качестве ключа. Вместо этого вы можете сделать имя «Планета». И даже если вам нужно найти планету, простой цикл, чтобы найти его, тоже хорош. В конце концов, вы не собираетесь иметь тысячи планет в солнечной системе, поэтому нет необходимости в более быстром поисковом механизме Словаря.

Преимущество списка состоит в том, что он сохраняет порядок, в котором вы добавляете элементы. Dictonary этого не делает, хотя есть и OrderedDictionary, если вам нужны обе функции.

Как бы то ни было, использование такого класса коллекций, в зависимости от ваших потребностей, избавит вас от необходимости использовать GetEnumerator (из интерфейса IEnumerable).

+1

Зачем использовать словарь, если вы только собираетесь использовать значения? Почему бы не использовать 'List ' тогда? –

+0

Вы также можете использовать список (который я предложил в тексте). Это зависит от использования. Словарь позволяет вам найти планету по имени в других сценариях. Linq тоже может это сделать, но словарь быстрее. – GolezTrol

+0

Тогда объясните, что в вашем ответе пожалуйста :) –

0

Вы создаете объекты для каждой планеты. foreach будет работать только на сбор. Лучшее создание Список planetList = new List();

и добавить планет к планетеList и применить foreach.