C#实现通用的IEnumerable

时间:2012-08-08 20:02:15

标签: c# generics interface ienumerable

我一直想知道是否有可能说State类实施IEnumerable<Person>IEnumerable<City>所以我可以通过foreach以及所有的所有人获得所有居住在该州的人城市。它甚至不会编译说:Error 1 'ConsoleApplication1.City' does not implement interface member 'System.Collections.IEnumerable.GetEnumerator()'(很奇怪)......这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Collections;

namespace ConsoleApplication1
{
    class Person
    {
    }

    class City : IEnumerable<Person>
    {
        // City has citizens:
        Person[] citizens;

        IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
        {
            foreach (Person p in citizens)
                yield return p;
        }
    }

    class State : IEnumerable<Person>, IEnumerable<City>
    {
        // State has cities:
        City[] cities;

        IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
        {
            foreach (City c in cities)
                foreach (Person p in c)
                    yield return p;
        }

        IEnumerator<City> IEnumerable<City>.GetEnumerator()
        {
            foreach (City c in cities)
                yield return c;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            State s = new State();
            foreach (Person p in s) ;
            foreach (City c in s) ;
        }
    }
}

3 个答案:

答案 0 :(得分:9)

问题是IEnumerable<T>还要求您实现IEnumerable(非通用版本)。您需要同时执行GetEnumerator()次调用。

话虽如此,这将变得非常棘手,因为你State类需要确定要枚举的内容。我个人会避免在一个类中实现两次IEnumerable<T>,而是将枚举作为方法返回:

class State : IEnumerable<City>
{
    public IEnumerable<Person> GetPeople()
    {
      // return people...

一般来说,我认为尝试将某些东西作为两种不同类型的枚举实际上是一种设计缺陷。最好让国家得到更好的实施:

public class State
{
    public IEnumerable<City> Cities { get { // return cities...

    public IEnumerable<People> People { get { // return people...

这将要求您(略微)更改您的使用情况,更像是:

foreach(Person person in theState.People)
{
    // ....

就我个人而言,我认为这对于StateCity来说都是更好的方法。我会这样写:

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{

    class Person
    {
    }

    class City
    {
        // City has citizens:
        Person[] citizens;

        public IEnumerable<Person> People
        {
            get
            {
                return citizens;
            }
        }
    }

    class State : IEnumerable<Person>, IEnumerable<City>
    {
        // State has cities:
        City[] cities;

        public IEnumerable<City> Cities
        {
            get
            {
                return cities;
            }
        }

        public IEnumerable<Person> AllPeople
        {
            get
            {
                return Cities.SelectMany(c => c.People);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            State s = new State();
            foreach (Person p in s.AllPeople) { /* Do something */ }
            foreach (City c in s.Cities) { /* Do something */ } 
        }
    }
}

我发现这一点要清楚得多 - 因为一个城市人,但它本身并不是人,等等。

答案 1 :(得分:2)

您也需要实现非泛型变体! System.Collections.IEnumerable是没有泛型类型参数的那个!

为System.Collections.Generic.IEnumerable.GetEnumerator添加一个显式接口实现 - 并使其抛出异常 - 您无法正确实现非泛型接口。

答案 2 :(得分:2)

这实际上是一个有趣的问题,因为Reed和Sebastian都指出了这一点,你也需要实现非泛型方法。但是,您只能实现一次,并且您有两个需要的接口。我认为更好的设计可能根本没有状态实现IEnumerable,但有两个属性People和Cities暴露IEnumerables。我认为这也是一个稍微方便(可发现)的API。