C# 枚举对象 foreach

C# Enumerating Object foreach

我在下面有一个我想做的简化版本。我有一个 class 行星供 class 太阳系使用。我想使用 foreach 循环为 SolarSystem 中的每个行星编写 orbitTimeInDays。

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

问题是枚举,我已经阅读了几篇关于使对象可枚举的文章和问题,但我似乎无法弄清楚如何将它应用到 SolarSystem 以便我可以检查它构造的每个 Planet。 (最终它还会包含小行星等,所以它不仅仅是 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...
    }
}

你的太阳系并没有告诉它可以迭代任何东西。你必须实现 IEnumerable 来告诉编译器:

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

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

这是可枚举的基本实现。它使用 yield 关键字为您即时生成一个枚举器。

您可以选择在您的 class 中创建一个 属性 Planets,大概是这样的:

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

然后你可以遍历 solarSystem.Planets.

这不可能像您这样做的方式。您可以创建 list/array 个行星,而不是为行星创建单个属性。这样你就可以从太阳系外创造新的行星。 ;-)

类似于:

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

您不能只枚举所有属性。也许最好的解决方案是给 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)

字典可让您通过名称快速查找行星,但如果不需要,您可以改用列表,它只包含值(行星),没有名称作为键。您可以改为将名称设为 Planet 的 属性。即使你需要找到一颗行星,一个简单的循环来找到它也是好的。毕竟,你不会在太阳系中拥有成千上万的行星,所以对字典的快速搜索机制没有太大的需求。

List 的一个优点是它保留了您添加元素的顺序。 Dictonary 没有,尽管也有 OrderedDictionary 以备不时之需。

无论如何,使用这样一个集合 class,无论哪个最适合您的需要,您都不必自己实现 GetEnumerator(从 IEnumerable 接口)。

您正在为每个行星创建对象。 foreach 仅适用于集合。 更好地创造 列出 planetList = new List();

并将行星添加到 planetList 并申请每个。