using Chernobyl.Event; using Chernobyl.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Chernobyl.Collections.Generic.Event { /// /// Combines two sequences into a single sequence. /// /// The type of the elements of the input sequences. public class Concatenation : IEventEnumerable { /// /// Initializes a new instance of the /// class. /// /// The first sequence to add to the second. /// The second sequence to add to the first. /// Thrown if /// or is null. public Concatenation(IEventEnumerable first, IEventEnumerable second) { first.ThrowIfNull("first"); second.ThrowIfNull("second"); // IEventEnumerable.ItemsAdded should also raise the // IEventEnumerable.ItemsAdded event. ItemsAdded += (sender, args) => { if (_itemsAdded != null) _itemsAdded(sender, args); }; // IEventEnumerable.ItemsRemoved should also raise the // IEventEnumerable.ItemsRemoved event. ItemsRemoved += (sender, args) => { if (_itemsRemoved != null) _itemsRemoved(sender, args); }; _first = first; _first.ItemsAdded += RaiseItemsAdded; _first.ItemsRemoved += RaiseItemsRemoved; _second = second; _second.ItemsAdded += RaiseItemsAdded; _second.ItemsRemoved += RaiseItemsRemoved; } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through /// the collection. /// public IEnumerator GetEnumerator() { return ((IEnumerable)_first).Concat(_second).GetEnumerator(); } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate /// through the collection. /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// An event that is raised right after items are added to this list. /// public event EventHandler> ItemsAdded; /// /// An event that is raised right after items are removed from this list. /// public event EventHandler> ItemsRemoved; /// /// An event that is raised right after items are added to this list. /// event EventHandler IEventEnumerable.ItemsAdded { add { _itemsAdded += value; } remove { _itemsAdded -= value; } } /// /// An event that is raised right after items are removed from this list. /// event EventHandler IEventEnumerable.ItemsRemoved { add { _itemsRemoved += value; } remove { _itemsRemoved -= value; } } /// /// Raises the event if it has event handlers. /// /// The sender of the event. This parameter will /// be replaced by this in the raised event. /// The instance /// containing the event data. void RaiseItemsAdded(object sender, ItemsEventArgs e) { if (ItemsAdded != null) ItemsAdded(this, e); } /// /// Raises the event if it has event handlers. /// /// The sender of the event. This parameter will /// be replaced by this in the raised event. /// The instance /// containing the event data. void RaiseItemsRemoved(object sender, ItemsEventArgs e) { if (ItemsRemoved != null) ItemsRemoved(this, e); } /// /// The first sequence to add to the second. /// readonly IEventEnumerable _first; /// /// The second sequence to add to the first. /// readonly IEventEnumerable _second; /// /// The backing field to . /// EventHandler _itemsAdded; /// /// The backing field to . /// EventHandler _itemsRemoved; } /// /// Extension and utility methods for . /// public static class ConcatenationExtensions { /// /// Combines two sequences into a single sequence. /// /// The type of the elements of the input sequences. /// The first sequence to add to the second. /// The second sequence to add to the first. /// An instance that contains the combined elements of the two /// input sequences. /// Thrown if /// or is null. public static IEventEnumerable Concat(this IEventEnumerable first, IEventEnumerable second) { return new Concatenation(first, second); } /// /// Combines multiple sequences into a single sequence. /// /// The type of the elements of the input sequences. /// The sequences that are to be combined. /// An instance that contains the combined elements of the /// input sequences. /// Thrown if /// is null. public static IEventEnumerable Concat(IEnumerable> sequences) { sequences.ThrowIfNull("sequences"); IEventEnumerable sequence; using (IEnumerator> iter = sequences.GetEnumerator()) { // If sequences contains no elements then we return an empty // IEventEnumerable{T}. sequence = iter.MoveNext() ? iter.Current : DecoratingEventEnumerable.Empty; while (iter.MoveNext()) { IEventEnumerable previousSequence = sequence; sequence = previousSequence.Concat(iter.Current); } } return sequence; } } }