1

我有如下的 PlayList 类。我喜欢歌曲 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();
    }
}

感谢您的建议!

4

2 回答 2

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

  2. 为此,我会使用Skipand ,即在方法中,这种方式要简单得多。TakeGetSong

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

  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
}
于 2013-12-24T15:41:49.737 回答
0

使用普通的旧枚举器:调用列表的 GetEnumerator ,然后对其进行迭代。这就是 foreach 在窗帘下所说的。这正是你想要的结构:它让你一个一个地迭代并记住你在迭代中的位置。

于 2013-12-24T14:46:37.093 回答