C#产量 跟进到最后.在我的课堂上



>我有如下类播放列表。我有播放列表实例收藏夹,歌曲 ID 为 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},我需要执行这个。

foreach(Song song in favorite.GetSong(4))
{
    //Somthing
}

这返回我ID为1,2,3,4的歌曲。接下来,我执行此代码。

foreach(Song song in favorite.GetSong(3))
{
    //Somthing
}

我需要 id 为 5、6、7 的返回歌曲。但我不知道该怎么做。我需要记住上次退回的项目,下次从下一个项目开始。如果我执行这个

foreach(Song song in favorite)
{
    //Somthing
}

我希望从上次返回的项目(在本例中为 7)返回播放列表中的所有歌曲以结束 (8, 9 , 10)。但这不是必需的。

internal class PlayList : IEnumerable<SongID>
{
    private List<SongID> songsInAlbum = new List<SongID>();
    public Song this[SongID id]
    {
        get
        {
            if (songsInAlbum.Contains(id))
            {
                return AllSongs[id];
            }
            throw new KeyNotFoundException();
        }
    }
    public IEnumerable<Song> GetSong(int maxReturn = Int32.MaxValue)
    {
        int wasReturned = 0;
        foreach (SongID id in songsInAlbum)
        {
            if (wasReturned < maxReturn)
            {
                yield return AllSong[id];
                wasReturned++;
            }
        }
    }
    public void AddSong(SongID id)
    {
        songsInAlbum.Add(id);
    }
    public IEnumerator<SongID> GetEnumerator()
    {
        return songsInAlbum.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

谢谢你的建议!

  1. 最好不要在这里违背惯例,那将是维护的噩梦。我将保持foreach预期行为。相反,您可以使用另一个重载来枚举其余歌曲

  2. 为此,我会使用 SkipTake,即GetSong方法中,这样更简单。

  3. GetSong 是返回序列的方法的糟糕名称。我会将其重命名为 GetSongs ,但我更喜欢更具描述性的名称,例如 GetNext 或只是 Next .

  4. 为了获得剩余的歌曲,另一个重载在这里更有意义。我是可选参数的粉丝,但在这种情况下,我不想要它。

所以我们来了

internal class PlayList : IEnumerable<SongID>
{
    private List<SongID> songsInAlbum = new List<SongID>();
    int currentIndex = 0; //maintain an index per instance; 1-based
    int Count //make it public if it makes sense
    {
        get { return songsInAlbum.Count; }
    }
    public Song this[SongID id]
    {
        get
        {
            if (songsInAlbum.Contains(id))
            {
                return AllSongs[id];
            }
            throw new KeyNotFoundException();
        }
    }
    public IEnumerable<Song> Next(int noOfSongs)
    {
        try 
        {
            return this.Skip(currentIndex).Take(noOfSongs).Select(x => AllSong[x]);
        }
        finally
        {
            if (currentIndex < Count)
                currentIndex += Math.Min(Count - currentIndex, noOfSongs);
        }
    }
    public IEnumerable<Song> Next() //or 'Rest', sounds good.
    {
        return Next(int.MaxValue); //less readable
        //or
        return Next(Count); //a more meaningful number
        //or
        return Next(Count - currentIndex); //for correctness
    }
    public void AddSong(SongID id)
    {
        songsInAlbum.Add(id);
    }
    public IEnumerator<SongID> GetEnumerator() //general enumerator, enumerates them all
    {
        return songsInAlbum.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

这样称呼它:

foreach(Song song in favorite.Next(4))
{
    //1, 2, 3, 4
}
foreach(Song song in favorite.Next(3))
{
    //5, 6, 7
}
foreach(Song song in favourite.Next())
{
    //8, 9, 10
}
foreach(Song song in favourite)
{
    //1, 2, ... 10
}

使用一个普通的旧枚举器:调用列表的 GetEnumerator,然后对其进行迭代。这就是窗帘下所说的。这是完全符合您期望的构造:它允许您逐个迭代并记住您在迭代中的位置。

相关内容

  • 没有找到相关文章

最新更新