Click here to Skip to main content
15,909,835 members
Articles / Programming Languages / C#

What is the use of c# “Yield” keyword ?

Rate me:
Please Sign up or sign in to vote.
4.84/5 (115 votes)
7 Apr 2014CPOL3 min read 250.2K   99   33
In this blog we will go through 2 important uses of c# yield keyword.
“Yield keyword helps us to do custom stateful iteration over .NET collections.”
 
There are two scenarios where “yield” keyword is useful:-
 
 
  • Customized iteration through a collection without creating a temporary collection.
  • Stateful iteration.
 
 
Scenario 1:- Customized iteration through a collection<o:p>
 

Let’s try to understand what customized iteration means with an example. Consider the below code.

 
Let say we have a simple list called as “MyList” which has collection of 5 continuous numeric values 1,2,3,4 and 5. This list is browsed/iterated from console application from within static void main method.
 

For now let’s visualize the “main()” method as a caller. So the caller i.e. “main()” method calls the list and displays the items inside it. Simple…till now Wink | <img src= ".

static List<int> MyList = new List<int>();

static void FillValues()
{
            MyList.Add(1);
            MyList.Add(2);
            MyList.Add(3);
            MyList.Add(4);
            MyList.Add(5);
}
static void Main(string[] args) // Caller
{
            FillValues(); // Fills the list with 5 values
            foreach (int i in MyList) // Browses through the list
            {
                Console.WriteLine(i);
            }
            Console.ReadLine();
}
Image 2
 
 
 
Now let me complicate this situation let’s say the caller only wants values greater than “3” from the collection. So the obvious thing as a c# developer we will do is create a function as shown below. This function will have temporary collection. In this temporary collection we will first add values which are greater than “3” and return the same to the caller. The caller can then iterate through this collection.
static IEnumerable<int> FilterWithoutYield()

{
            List<int> temp = new List<int>();
            foreach (int i in MyList)
            {
                if (i > 3)
                {
                    temp.Add(i);
                }
            }
            return temp;
} 

 

 
 
Image 3
 
 
 
Now the above approach is fine but it would be great if we would get rid of the collection, so that our code becomes simple. This where “yield” keyword comes to help. Below is a simple code how we have used yield.
 
“Yield” keyword will return back the control to the caller, the caller will do his work and re-enter the function from where he had left and continue iteration from that point onwards. In other words “yield” keyword moves control of the program to and fro between caller and the collection.
static IEnumerable<int> FilterWithYield()

{
            foreach (int i in MyList)
            {
                if (i > 3) yield return i;
            }
}  
 
 

So for the above code following are details steps how the control will flow between caller and collection. You can also see the pictorial representation in the next diagram shown below.

 
  • Step 1:- Caller calls the function to iterate for number’s greater than 3.
  • Step 2:- Inside the function the for loop runs from 1 to 2 , from 2 to 3 until it encounters value greater than “3” i.e. “4”. As soon as the condition of value greater than 3 is met the “yield” keyword sends this data back to the caller.
  • Step 3:- Caller displays the value on the console and re-enters the function for more data. This time when it reenters, it does not start from first. It remembers the state and starts from “5”. The iteration continues further as usual.
 

Image 4

 

 

 

 

 

 

 

Scenario 2:- Stateful iteration<o:p>

Now let us add more complications to the above scenario. Let’s say we want to display running total of the above collection. What do I mean?.

In other words we will browse from 1 to 5 and as we browse we would keep adding the total in variable. So we start with “1” the running total is “1”, we move to value “2” the running total is previous value “1” plus current value “2” i.e. “3” and so on.

Below is the pictorial representation of the running total looks like.

 
Image 5


In other words we would like to iterate through the collection and as we iterate would like to maintain running total state and return the value to the caller ( i.e. console application). So the function now becomes something as shown below. The “runningtotal” variable will have the old value every time the caller re-enters the function.

 

 

static IEnumerable<int> RunningTotal()
         {
             int runningtotal=0;
             foreach(int i in MyList)
             {
                  runningtotal += i;
                 yield return (runningtotal);
                 
             }
         }
 
Below goes the caller code and output.
foreach (int i in RunningTotal())

            {
                Console.WriteLine(i);
            } 
            Console.ReadLine(); 

<o:p>

 
 
Image 6
 
 

Video on use of C# “Yield” keyword

Image 7

For Further reading do watch  the below interview preparation videos and step by step video series.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect https://www.questpond.com
India India

Comments and Discussions

 
GeneralRe: My vote of 4 Pin
jfriedman11-Apr-13 20:50
jfriedman11-Apr-13 20:50 
What do you think of this?

C#
#region EnumerableSegment

    /// <summary>
    /// Enumerable base class with offset and count.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EnumerableSegment<T> : IEnumerable<T>, IEnumerator<T>
    {
        bool m_Disposed;
        T t;
        internal protected readonly int VirtualIndex, VirtualCount;
        
        public int Index { get; protected set;}

        public int Count { get { return VirtualCount; } }

        public virtual T Current
        {
            get { if (Index == -1) throw new InvalidOperationException("Enumeration has not started call MoveNext"); return t; }
            internal protected set { t = value; }
        }

        void IDisposable.Dispose()
        {
            m_Disposed = true;
        }

        public virtual bool MoveNext()
        {
            if (m_Disposed) return false;
            else return ++Index <= VirtualCount;
        }

        object System.Collections.IEnumerator.Current
        {
            get { if (Index == -1) throw new InvalidOperationException("Enumeration has not started call MoveNext"); return t; }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            if (m_Disposed) return false;
            else return MoveNext();
        }

        void System.Collections.IEnumerator.Reset()
        {
            if (m_Disposed) return;
            Index = VirtualIndex;
            t = default(T);
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            if (m_Disposed) return null; return this;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            if (m_Disposed) return null; return this;
        }

        public virtual int Remaining
        {
            get { if (m_Disposed) return 0; return Index > VirtualCount ? 0 :  VirtualCount - Index; }
        }

        public EnumerableSegment(IEnumerable<T> enumerable, int start = 0, int count = -1)
        {
            Index = VirtualIndex = start;
            VirtualCount = count;
        }

        public EnumerableSegment(T item)
        {
            VirtualIndex  = Index = 0;
            VirtualCount = 1;
        }

        public EnumerableSegment() { Index = -1; }

        public virtual void Reset() { Index = VirtualIndex; }

        public static void ForAll(IEnumerable<T> enumerable, Action<T> action, int index = 0, int count = -1)
        {
            foreach (T t in new EnumerableSegment<T>(enumerable, index, count)) 
                action(t);
        }

        public static bool Any(IEnumerable<T> enumerable, Func<T, bool> predicate, int index = 0, int count = -1)
        {
            foreach (T t in new EnumerableSegment<T>(enumerable, index, count))
                if (predicate(t)) return true;
            return false;
        }

        //--

    }

    #endregion

    #region Stream Classes

    #region EnumerableByteStream

    public class EnumerableByteStream : EnumerableSegment<byte>, IEnumerable<byte>, IEnumerator<byte>, IList<byte>
    {
        protected int m_Current;

        internal protected System.IO.Stream m_Stream;

        internal protected bool m_Disposed;

        internal EnumerableByteStream m_Self;

        bool Initialized { get { return CurrentInt != -1; } }

        public int CurrentInt { get { return Current; } }

        public EnumerableByteStream(byte Byte) : this(Byte.Yield()) { }

        public EnumerableByteStream(IEnumerable<byte> bytes, int? index = null, int? count = null)
            : base(bytes, index ?? 0, (int)(count.HasValue ? count - index : -1)){}

        public EnumerableByteStream(System.IO.Stream stream, int? index = null, int? count = null)
            : this(null as IEnumerable<byte>, index ?? (int)stream.Position, count ?? (int)stream.Length)
        {
            m_Stream = stream;
            m_Current = Current;
        }

        //public override int Remaining
        //{
        //    get
        //    {
        //        return (int)(m_Stream .Length + base.Remaining);
        //    }
        //}

        public IEnumerable<byte> ToArray(int offset, int count, byte[] buffer)
        {
            if (offset < 0) throw new ArgumentOutOfRangeException("offset must refer to a location within the buffer.");
            else if (count + offset > Length) throw new ArgumentOutOfRangeException("count must refer to a location within the buffer with respect to offset.");

            if (count == 0) return Enumerable.Empty<byte>();
            buffer = buffer ?? new byte[count];
            int len = count;
            while ((len -= m_Stream.Read(buffer, offset, count)) > 0
                &&
                Remaining > 0)
            {
                //
            }
            return buffer;
        }

        public IEnumerator<byte> GetEnumerator()
        {
            if (CurrentInt == -1) MoveNext();
            while (!m_Disposed && MoveNext()) yield return Current = (byte)m_Current;
        }

        public override bool MoveNext()
        {
            if (base.MoveNext()) return CoreGetEnumerator() != -1;
            return false;
        }

        int CoreGetEnumerator(long direction = 1)
        {
            if (!m_Disposed && m_Stream.Position < Count) return Current = (byte)(m_Current = m_Stream.ReadByte());
            else unchecked { return Current = (byte)(m_Current = -1); }
        }

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

        internal protected long CoreIndexOf(IEnumerable<byte> items, int start = -1, int count = -1)
        {
            if (m_Stream == null || m_Disposed || items == null || items == Enumerable.Empty<byte>() || count == 0) return -1;
            if (count == -1) count = items.Count();

            if (!Initialized && !MoveNext()) return -1;

            if (start != -1 && start + count > Count) return -1;
            else if (start != -1 && start != Position) if (m_Stream.CanSeek) m_Stream.Seek(start, System.IO.SeekOrigin.Begin);
                else return -1;//throw new InvalidOperationException("The underlying stream must be able to seek if the start index is specified and not equal to -1");

            using (IEnumerator<byte> itemPointer = items.Skip(start).Take(count).GetEnumerator())
            {
                if (!itemPointer.MoveNext()) return -1;
                //We start at 
                long position = Position;
                if (start == -1 && m_Stream.CanSeek && m_Stream.Position != 0 && itemPointer.Current != Current)
                {
                    Reset();
                }
                else start = (int)m_Stream.Position;
                //While there is an itemPointer
                while (itemPointer != null)
                {
                    int j = count;
                    while (itemPointer.Current == Current && (--j > 0))
                    {
                        if (!itemPointer.MoveNext()) break;
                    }
                    //The match is complete
                    if (j == 0)
                    {
                        //If CanSeek and moved the position and we will go back to where we were
                        //if (m_Stream.CanSeek && position != Position) m_Stream.Seek(position, System.IO.SeekOrigin.Begin); //Curent and Begin need to be aware...
                        return m_Stream.Position - 1; //-1 Because a byte was read to obtain Current
                    }
                    if (!MoveNext()) break;
                }
                if (start == -1 && m_Stream.CanSeek && position != Position) m_Stream.Seek(position, System.IO.SeekOrigin.Begin);
                return -1;
            }
        }

        internal protected int CoreIndexOf(byte item, int start, int count) { return (int)CoreIndexOf(item.Yield(), start, count); }

        public virtual int IndexOf(byte item)
        {
            return CoreIndexOf(item, -1, 1);
        }

        public virtual void Insert(int index, byte item)
        {

            //System.IO.MemoryStream newMemory = new System.IO.MemoryStream(Count + 1);
            //System.IO.Stream oldMemory;
            //using (EnumerableByteStream preSegment = new EnumerableByteStream(m_Stream, 0, index - 1))
            //{
            //    using (EnumerableByteStream postSegment = new EnumerableByteStream(m_Stream, index - 1, Count - index + 1))
            //    {
            //        foreach (byte b in preSegment) newMemory.WriteByte(b);
            //        newMemory.WriteByte(item);
            //        foreach (byte b in postSegment) newMemory.WriteByte(b);
            //    }
            //}
            //oldMemory = m_Stream;
            //m_Stream = newMemory;
            //oldMemory.Dispose();

            //Linked stream around origional bytes up to index
            //additional byte
            //Rest of old stream
            //long preInsert = m_Stream.Position;
            EnumerableByteStream newPointer =new EnumerableByteStream((new EnumerableByteStream(m_Stream, 0, index - 1) as IEnumerable<byte>).
                Concat(item.Yield()).
                Concat(new EnumerableByteStream(m_Stream, index - 1, Count - index + 1) as IEnumerable<byte>));
            //m_Stream = LinkedStream.LinkAll(new EnumerableByteStream(m_Stream, 0, index - 1), new EnumerableByteStream(item), new EnumerableByteStream(m_Stream, index - 1, Count - index + 1));
            m_Self = newPointer;
            //m_Stream.Position = preInsert;
        }

        public virtual void RemoveAt(int index)
        {
            //Linked stream around index
            m_Stream = LinkedStream.LinkAll(new EnumerableByteStream(m_Stream, 0, index), new EnumerableByteStream(m_Stream, ++index, Count - index));
        }

        /// <summary>
        /// Sets or Retrieves a byte from the underlying stream
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public virtual byte this[int index]
        {
            get
            {
                if (index < 1) index = 0;
                if (index != m_Stream.Position)
                {
                    if (m_Stream.CanSeek) m_Stream.Seek(index, System.IO.SeekOrigin.Begin);
                    else throw new InvalidOperationException("You can only move the index if the underlying stream CanSeek");
                }
                return (byte)m_Stream.ReadByte();
            }
            set
            {
                if (m_Stream.CanWrite && m_Stream.CanSeek) m_Stream.Seek(index, System.IO.SeekOrigin.Begin);
                else throw new InvalidOperationException("You can logically set a byte in the stream the index if the underlying stream supports CanWrite and CanSeek");
                m_Stream.Write(value.Yield().ToArray(), 0, 1);
            }
        }

        public virtual void Add(byte item)
        {
            if (m_Stream.CanWrite) m_Stream.Write(item.Yield().ToArray(), 0, 1);
            else throw new InvalidOperationException("You can logically set a byte in the stream the index if the underlying stream supports CanWrite");
        }

        /// <summary>
        /// Erases all bytes in perspective of the EnumerableByteStream
        /// </summary>
        /// <remarks>
        /// Creates a new <see cref="System.IO.MemoryStream"/> in the place of the m_Stream.
        /// </remarks>
        public virtual void Clear()
        {
            m_Stream = new System.IO.MemoryStream();
            return;
        }

        public virtual bool Contains(byte item)
        {
            //See CachingEnumerableByteStream on why not < -1
            return CoreIndexOf(item, 0, 1) != -1;
        }

        /// <summary>
        /// Advanced the underlying System.IO.Stream by reading into the given array
        /// </summary>
        /// <param name="array">The array to read into</param>
        /// <param name="arrayIndex">The index into the given array to stary copying at</param>
        public virtual void CopyTo(byte[] array, int arrayIndex)
        {
            CoreCopyTo(array, arrayIndex);
        }

        public virtual void CopyTo(System.IO.Stream stream, int? bufferSize = null)
        {
            m_Stream.CopyTo(stream, (int)(stream.Length - stream.Position)); 
        }

        public virtual void CoreCopyTo(byte[] array, int arrayIndex, int length = -1)
        {
            if (length <= 0) return;
            if (length == -1) length = array.Length - arrayIndex;
            else if (length > m_Stream.Length) throw new ArgumentOutOfRangeException("Can't copy more bytes then are availble from the stream");
            m_Stream.Read(array, arrayIndex, length);
        }

        public long Position { get { return Index; } }

        public virtual long Length
        {
            get { return Count; }
        }        

        public virtual bool IsReadOnly
        {
            get { return m_Stream.CanWrite; }
        }

        public virtual bool Remove(byte item)
        {
            //Create N new EnumerableByteStreams with the items index noted in each iteration.
            //For each occurance of item in the underlying stream place an index
            //For each index create a new EnumerableByteStream with the index = i and the count = 1
            //m_Stream = new LinkedStream(parts)
            //return true if any of this happened 
            return false;
        }

        public static implicit operator System.IO.Stream(EnumerableByteStream eByteStream) { return eByteStream.m_Stream; }

        object System.Collections.IEnumerator.Current
        {
            get { return GetEnumerator().Current; }
        }

        public override void Reset()
        {
            m_Current = -1;
            if (m_Stream.CanSeek) m_Stream.Seek(VirtualIndex, System.IO.SeekOrigin.Begin);
            base.Reset();
        }

        public long Seek(long offset, System.IO.SeekOrigin origin) { if (m_Stream.CanSeek) return m_Stream.Seek(offset, origin); return m_Stream.Position; }
    }

    #endregion

    #region CachingEnumerableByteStream

    //Todo Test and Complete, use LinkedStream if required
    //Aims to be a type of constrained stream as well give the ability to cache previous read bytes which may no longer be able to be read from the stream
    public class CachingEnumerableByteStream : EnumerableByteStream
    {
        //Same as above but with a Cache for previously read bytes
        List<byte> m_ReadCache = new List<byte>(), m_WriteCache = new List<byte>();

        public CachingEnumerableByteStream(System.IO.Stream stream)
            : base(stream)
        {
        }

        internal void EnsureCache(int index)
        {
            try
            {
                //Read Ahead
                if (index > m_ReadCache.Count)
                {
                    byte[] buffer = new byte[index - m_Stream.Position];
                    CopyTo(buffer, 0);
                    m_ReadCache.AddRange(buffer);
                }
            }
            catch { throw; }
        }

        public override byte this[int index]
        {
            get
            {
                EnsureCache(index);
                return m_ReadCache[index];
            }
            set
            {
                //Read Ahead
                EnsureCache(index);
                base[index] = m_ReadCache[index] = value;
            }
        }
    }

    #endregion

    #region LinkedStream

    /// <summary>
    /// Represtents multiple streams as a single stream.
    /// </summary>
    /// <remarks>
    /// Turning into a interesting little looping buffer when you just call AsPerpetual, would be a cool idea for a RingBuffer
    /// </remarks>
    public class LinkedStream :
        System.IO.Stream, //LinkedStream is a System.IO.Stream
        IEnumerable<EnumerableByteStream>, //Which happens to be IEnumerable of more Stream's
        IEnumerator<EnumerableByteStream>, //It can maintain the state of those Stream's which it is IEnumerable
        IEnumerable<byte>, //It can be thought of as a single contagious allocation of memory to callers
        IEnumerator<byte>//It can maintain a state of those bytes in which it enumerates
    {
        #region Fields

        internal protected IEnumerable<EnumerableByteStream> m_Streams;

        internal protected ulong m_AbsolutePosition;

        internal protected IEnumerator<EnumerableByteStream> m_Enumerator;

        internal EnumerableByteStream m_CurrentStream;

        internal int m_StreamIndex = 0;

        internal protected bool m_Disposed;

        #endregion

        #region Propeties

        public System.IO.Stream CurrentStream
        {
            get
            {
                if (m_Disposed) return null;
                if (m_CurrentStream == null) m_CurrentStream = m_Enumerator.Current;
                return m_CurrentStream;
            }
        }

        public override bool CanRead
        {
            get { return !m_Disposed && CurrentStream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return !m_Disposed && CurrentStream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return !m_Disposed && CurrentStream.CanWrite; }
        }

        public override void Flush()
        {
            if (!m_Disposed) CurrentStream.Flush();
        }

        public override long Length
        {
            get { return (long)TotalLength; }
        }

        public ulong TotalLength
        {
            get
            {
                if (m_Disposed) return 0;
                ulong totalLength = 0;
                foreach (EnumerableByteStream stream in this as IEnumerable<EnumerableByteStream>) totalLength += (ulong)(stream.Count);
                return totalLength;
            }
        }

        public override long Position
        {
            get
            {
                return (long)TotalPosition;
            }
            set
            {
                if (!m_Disposed) SeekAbsolute(value, System.IO.SeekOrigin.Current);
            }
        }

        public ulong TotalPosition
        {
            ///The total position is the m_AbsolutePosition and the currentPosition which is free roaming
            get { return m_Disposed ? 0 : m_AbsolutePosition + (ulong)m_CurrentStream.Position; }
            protected internal set { if (m_Disposed) return; m_AbsolutePosition = value; }
        }

        #endregion

        #region Constructors

        public LinkedStream(IEnumerable<EnumerableByteStream> streams)
        {
            if (streams == null) streams = Enumerable.Empty<EnumerableByteStream>();
            m_Streams = streams;
            m_Enumerator = GetEnumerator();
            m_Enumerator.MoveNext();
        }

        public LinkedStream(EnumerableByteStream stream) : this(stream.Yield()) { }


        public static LinkedStream LinkAll(params EnumerableByteStream[] streams) { return new LinkedStream(streams); }

        #endregion

        #region Methods

        /// <summary>
        /// Creates a new MemoryStream with the contents of all sub streams
        /// </summary>
        /// <returns>The resulting MemoryStream</returns>
        public System.IO.MemoryStream Flatten()
        {
            System.IO.MemoryStream memory = new System.IO.MemoryStream((int)TotalLength);
            foreach (System.IO.Stream stream in m_Streams) stream.CopyTo(memory);
            return memory;
        }

        public LinkedStream Link(params EnumerableByteStream[] streams) { return new LinkedStream(m_Streams.Concat(streams)); }

        public LinkedStream Link(EnumerableByteStream stream) { return Link(stream.Yield().ToArray()); }

        public LinkedStream Unlink(int streamIndex, bool reverse = false)
        {
            if (streamIndex > m_Streams.Count()) throw new ArgumentOutOfRangeException("index cannot be greater than the amount of contained streams");
            IEnumerable<EnumerableByteStream> streams = m_Streams;
            if (reverse) streams.Reverse();
            return new LinkedStream(m_Streams.Skip(streamIndex));
        }

        public LinkedStream SubStream(ulong absoluteIndex, ulong count)
        {

            LinkedStream result = new LinkedStream(new EnumerableByteStream(new System.IO.MemoryStream()));

            if (count == 0) return result;

            while (absoluteIndex > 0)
            {
                //absoluteIndex -= Read(// StreamOverload
            }

            return result;
        }

        internal void SelectStream(int logicalIndex)
        {
            if (m_Disposed) return;
            //If the stream is already selected return
            if (m_StreamIndex == logicalIndex) return;
            else if (logicalIndex < m_StreamIndex) m_Enumerator.Reset(); //If the logicalIndex is bofore the stream index then reset
            while (logicalIndex > m_StreamIndex) MoveNext();//While the logicalIndex is > the stream index MoveNext (casues m_StreamIndex to be increased).
        }

        internal void SelectStream(ulong absolutePosition)
        {
            if (m_Disposed) return;
            if (TotalPosition == absolutePosition) return;
            else if (absolutePosition < TotalPosition) m_Enumerator.Reset(); //If seeking to a position before the TotalPosition reset
            //While the total postion is not in range
            while (TotalPosition < absolutePosition)
            {
                //Move to the next stream (causing TotalPosition to advance by the current streams length), if we cant then return
                if (!MoveNext()) return;
                //subtract the length of the stream we skipped from the absolutePosition
                if (CurrentStream.Length > 0) absolutePosition -= (ulong)CurrentStream.Length;
            }
        }

        #endregion

        #region Wrappers

        public override int ReadByte()
        {
            return CurrentStream.ReadByte();
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return CoreRead(buffer, offset, count);
        }

        internal protected int CoreRead(byte[] buffer, long offset, long count, System.IO.SeekOrigin readOrigin = System.IO.SeekOrigin.Current)
        {
            switch (readOrigin)
            {
                case System.IO.SeekOrigin.Begin:
                    {
                        Seek(offset, System.IO.SeekOrigin.Begin);
                        goto case System.IO.SeekOrigin.Current;
                    }
                case System.IO.SeekOrigin.End:
                    {
                        //Seek to the end
                        MoveToEnd();

                        //Use the current case
                        goto case System.IO.SeekOrigin.Current;
                    }
                case System.IO.SeekOrigin.Current:
                    {
                        int read = 0;
                        while (read < count)
                        {
                            if (CurrentStream.Position < offset && CurrentStream.CanSeek) CurrentStream.Seek(offset, System.IO.SeekOrigin.Begin);
                            read += CurrentStream.Read(buffer, (int)offset, (int)count - (int)read);
                            if (CurrentStream.Position >= CurrentStream.Length && read < count) if (!MoveNext()) break;
                            //if (read != -1) m_AbsolutePosition += (uint)read;
                        }
                        return read;
                    }
                default:
                    {
                        Utility.BreakIfAttached();
                        break;
                    }
            }
            return 0;
        }

        bool MoveNext()
        {
            if (m_Disposed || m_Streams == null || m_Enumerator == null) return false;
            //If the current stream can seek it's not a big deal to reset it now also
            //if (m_CurrentStream.CanSeek) m_CurrentStream.Seek(0, System.IO.SeekOrigin.Begin);
            m_AbsolutePosition += (ulong)(m_CurrentStream.Count - m_CurrentStream.Position); //Cumulate the position of the non seeking stream - what was already read
            //Advance the stream index
            ++m_StreamIndex;
            //Return the result of moving the enumerator to the next available streeam
            return m_Enumerator.MoveNext();
        }

        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            switch (origin)
            {
                case System.IO.SeekOrigin.End:
                case System.IO.SeekOrigin.Begin:
                    return (long)SeekAbsolute(offset, System.IO.SeekOrigin.Begin);
                case System.IO.SeekOrigin.Current:
                    return m_CurrentStream.Seek(offset, origin);
                default: return m_CurrentStream.Position;
            }
        }

        public void MoveToEnd()
        {
            //While thre is a stream to advance
            while (MoveNext())
            {
                //Move the current stream to it's last position
                CurrentStream.Position = CurrentStream.Length;
            }
        }

        public ulong SeekAbsolute(long offset, System.IO.SeekOrigin origin)
        {
            switch (origin)
            {
                case System.IO.SeekOrigin.Current:
                    {

                        //Determine how many bytes to read in terms of long
                        long offsetPosition = (long)TotalPosition - offset;
                        if (offsetPosition < 0) CurrentStream.Seek(offsetPosition, System.IO.SeekOrigin.Current);
                        else CurrentStream.Position = offsetPosition;
                        return TotalPosition;
                    }
                case System.IO.SeekOrigin.Begin:
                    {
                        SelectStream((ulong)offset);
                        goto case System.IO.SeekOrigin.Current;
                    }
                case System.IO.SeekOrigin.End:
                    {
                        MoveToEnd();
                        goto case System.IO.SeekOrigin.Current;
                    }
                default:
                    {
                        Utility.BreakIfAttached();
                        break;
                    }
            }
            return m_AbsolutePosition;
        }



        IEnumerator<EnumerableByteStream> GetEnumerator() { return m_Disposed ? null : m_Streams.GetEnumerator(); }

        public override void SetLength(long value)
        {
            //If the position is < value set the position to the value first which will update CurrentStream if required.
            if (value < Length) Position = (long)m_AbsolutePosition + value;
            //Set the length of the current stream 
            CurrentStream.SetLength(value);
            m_AbsolutePosition = (ulong)value;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            if (count < CoreWrite(buffer, (ulong)offset, (ulong)count))
            {
#if DEBUG
                Utility.BreakIfAttached();
#endif
            }
        }

        ///Todo => Test and complete
        internal protected int CoreWrite(byte[] buffer, ulong offset, ulong count, System.IO.SeekOrigin readOrigin = System.IO.SeekOrigin.Current)
        {
            //Select the stream to write based on the offset
            SelectStream((ulong)offset);
            switch (readOrigin)
            {
                case System.IO.SeekOrigin.Current:
                    {
                        return (this as IEnumerator<System.IO.Stream>).Current.Read(buffer, (int)offset, (int)count);
                    }
                case System.IO.SeekOrigin.Begin:
                    {
                        return (this as IEnumerator<System.IO.Stream>).Current.Read(buffer, (int)offset, (int)count);
                    }
                case System.IO.SeekOrigin.End:
                    {
                        return (this as IEnumerator<System.IO.Stream>).Current.Read(buffer, (int)offset, (int)count);
                    }
                default:
                    {
#if DEBUG
                        Utility.BreakIfAttached();
#endif
                        break;
                    }
            }
            return 0;
        }

        IEnumerator<EnumerableByteStream> IEnumerable<EnumerableByteStream>.GetEnumerator()
        {
            return m_Streams.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return m_Streams.GetEnumerator();
        }

        EnumerableByteStream IEnumerator<EnumerableByteStream>.Current
        {
            get { return GetEnumerator().Current; }
        }

        void IDisposable.Dispose()
        {
            m_Disposed = true;
            if (m_Streams != null) m_Streams = null;
            m_StreamIndex = -1;
            base.Dispose();
        }

        void System.Collections.IEnumerator.Reset()
        {
            foreach (EnumerableByteStream stream in m_Streams) if (stream.m_Stream.CanSeek) stream.Seek(0, System.IO.SeekOrigin.Begin);
            GetEnumerator().Reset();
        }

        object System.Collections.IEnumerator.Current
        {
            get { return CurrentStream; }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            return MoveNext();
        }

        IEnumerator<byte> IEnumerable<byte>.GetEnumerator() { return new EnumerableByteStream(this as IEnumerable<byte>).GetEnumerator(); }

        byte IEnumerator<byte>.Current { get { return (this as IEnumerable<byte>).GetEnumerator().Current; } }

        #endregion
    }

    #endregion

    #endregion


I think its a unique use of the concept and I am wondering what others think!
GeneralRe: My vote of 4 Pin
  Forogar  8-Apr-14 7:45
professional  Forogar  8-Apr-14 7:45 
GeneralRe: My vote of 4 Pin
jfriedman8-Apr-14 8:42
jfriedman8-Apr-14 8:42 
GeneralRe: My vote of 4 Pin
  Forogar  8-Apr-14 8:56
professional  Forogar  8-Apr-14 8:56 
GeneralRe: My vote of 4 Pin
jfriedman30-Apr-14 14:33
jfriedman30-Apr-14 14:33 
GeneralRe: My vote of 4 Pin
  Forogar  1-May-14 6:02
professional  Forogar  1-May-14 6:02 
QuestionA couple of questions. Pin
George Swan10-Apr-13 20:04
mveGeorge Swan10-Apr-13 20:04 
AnswerRe: A couple of questions. Pin
Shivprasad koirala10-Apr-13 20:25
Shivprasad koirala10-Apr-13 20:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.