It's better not to go against convention here, that will be maintenance nightmare. I'll keep the expected behaviour of
foreach
. Instead you can have another overload to enumerate the rest of the songs.I would use
Skip
andTake
for this purpose, ie inGetSong
method, much simpler that way.GetSong
is a poor name for a method that returns a sequence. I would rename it toGetSongs
, but I prefer a more descriptive name likeGetNext
or justNext
.To get the remaining songs, another overload makes more sense here. I'm a fan of optional arguments, but in this case I wouldn't want it.
So here we go
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();
}
}
Call it like:
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
}