C#: IEnumerable, GetEnumerator,一个简单、简单的例子!

27

尝试创建一个超级简单的类来实现获取枚举器,但由于缺乏简单/不起作用的示例而彻底失败。我想做的就是创建一个数据结构的包装器(在这种情况下是列表,但我以后可能需要一个字典)并添加一些函数。

public class Album
{
    public readonly string Artist;
    public readonly string Title;
    public Album(string artist, string title)
    {
         Artist = artist;
         Title = title;
    } 
}
public class AlbumList
{
    private List<Album> Albums = new List<Album>;
    public Count { get { return Albums.Count; } }

    .....
    //Somehow GetEnumerator here to return Album
}

谢谢!

4个回答

36

您可以简单地返回由List<T>.GetEnumerator返回的枚举器:

public class AlbumList : IEnumerable<Album>
{
    // ...

    public IEnumerator<Album> GetEnumerator()
    {
        return this.albums.GetEnumerator();
    }

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

1
你好, 我尝试了上面的代码,但在这一行IEnumerator IEnumerable.GetEnumerator()上出现了编译器错误:"使用泛型类型'System.Collections.Generic.IEnumerator<T>'需要1个类型参数"。 - Andrew White
2
@Andrew White:不带泛型类型参数的IEnumerable/IEnumerator位于System.Collections命名空间中。 - dtb

15

除了其他答案之外,如果您需要更多控制枚举器的工作方式,或者有自定义枚举器的要求超出底层数据结构所提供的范围,则可以使用 yield 关键字。

public class AlbumList : IEnumerable<Album>
{
  public IEnumerator<Album> GetEnumerator()
  {
    foreach (Album item in internalStorage)
    {
      // You could use conditional checks or other statements here for a higher
      // degree of control regarding what the enumerator returns.
      yield return item;
    }
  }
}

1
+1 我喜欢你提出的更细粒度控制返回列表的额外观点。谢谢。 - HOKBONG
这让我把大约十行代码缩减成了一行代码。 - ouflak

10
using System.Collections;
using System.Collections.Generic;

public class AlbumList : IEnumerable<Album>
{
    private List<Album> Albums = new List<Album>();
    
    public int Count => Albums.Count;

    public IEnumerator<Album> GetEnumerator()
    {
        return this.Albums.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
或者简化版:
public class AlbumList
{
    private List<Album> Albums = new List<Album>();
    
    public int Count => Albums.Count;

    public IEnumerator<Album> GetEnumerator()
    {
        return this.Albums.GetEnumerator();
    }
}

我不建议删除 IEnumerable<T> 接口,因为这样会失去与 .NET 的集成,例如使用 LINQ 的可能性,但是你可以在 C# 中使用 foreach 遍历集合。

或者这个更简短 :-)

public class AlbumList : List<Album>
{
}

当然,最后这个列表是可变的,这可能不完全符合您的要求。


嗨, 尝试了上面的第一个例子,但在这一行出现了编译器错误: IEnumerator IEnumerable.GetEnumerator() “使用通用类型'System.Collections.Generic.IEnumerator<T>'需要1个类型参数”? - Andrew White
1
你可能忘记在你的C#文件顶部添加using System.Collections这一行。 - Steven

2

根据您的评论,您希望在数据结构(列表)周围有一个包装器,并且有一个枚举器函数返回一个Album,我认为您在谈论索引器属性,对吗?以下是实现方法:

public class Album
{
    public readonly string Artist;
    public readonly string Title;
    public Album(string artist, string title)
    {
         Artist = artist;
         Title = title;
    } 
}

public class AlbumList
{
    private List<Album> Albums = new List<Album>();
    public int Count
    {
        get { return Albums.Count; }
    }

    public Album this[int index]
    {
        get
        {
            return Albums[index];
        }
    }

    public Album this[string albumName]
    {
        get
        {
            return Albums.FirstOrDefault(c => c.Title == albumName);
        }
    }

    public void Add(Album album)
    {
        Albums.Add(album);
    }

    public void Remove(Album album)
    {
        Albums.Remove(album);
    }
}

一个小型控制台程序:
        AlbumList albums = new AlbumList();
        albums.Add(new Album { Artist = "artist1", Title = "title1" });
        albums.Add(new Album { Artist = "artist2", Title = "title2" });

        for (int i = 0; i < albums.Count; i++)
        {
            Console.WriteLine(albums[i].Artist);
            Console.WriteLine(albums[i].Title);
        }

        Console.WriteLine("title for artist1");
        Console.WriteLine(albums["artist1"].Title);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接