>我有如下类播放列表。我有播放列表实例收藏夹,歌曲 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();
}
}
谢谢你的建议!
-
最好不要在这里违背惯例,那将是维护的噩梦。我将保持
foreach
的预期行为。相反,您可以使用另一个重载来枚举其余歌曲。 -
为此,我会使用
Skip
和Take
,即GetSong
方法中,这样更简单。 -
GetSong
是返回序列的方法的糟糕名称。我会将其重命名为GetSongs
,但我更喜欢更具描述性的名称,例如GetNext
或只是Next
. -
为了获得剩余的歌曲,另一个重载在这里更有意义。我是可选参数的粉丝,但在这种情况下,我不想要它。
所以我们来了
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,然后对其进行迭代。这就是窗帘下所说的。这是完全符合您期望的构造:它允许您逐个迭代并记住您在迭代中的位置。