using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using Chernobyl.Event; using Chernobyl.Values; namespace Chernobyl.Collections.Generic.Event { /// /// An that can represent another /// (the "source") while still allowing the /// source to be swapped out with another /// at any time. /// /// The type that is to be held in this instance. public class SourceEventEnumerable : IEventEnumerable { /// /// Initializes a new instance of the class. /// public SourceEventEnumerable() : this(null) {} /// /// Initializes a new instance of the class. /// /// The source of the items that are being enumerated /// and the events that are raised. If null is specified then this /// instance will be empty. public SourceEventEnumerable(IEventEnumerable source) { Source = source; // When ItemsAdded/ItemsRemoved is invoked we'll want to also invoke // IEventEnumerable.ItemsAdded/IEventEnumerable.ItemsRemoved. ItemsAdded += (sender, e) => { if (_itemsAdded != null) _itemsAdded(this, e); }; ItemsRemoved += (sender, e) => { if (_itemsRemoved != null) _itemsRemoved(this, e); }; } /// /// The source of the items that are being enumerated and the events that /// are raised. If null is specified then this instance will be /// empty. /// public IEventEnumerable Source { get { return _source; } set { IEventEnumerable previousValue = _source; _source = value; if (previousValue != null) { previousValue.ItemsAdded -= OnSourceItemsAdded; previousValue.ItemsRemoved -= OnSourceItemsRemoved; } if (_source != null) { _source.ItemsAdded += OnSourceItemsAdded; _source.ItemsRemoved += OnSourceItemsRemoved; } } } /// /// 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; /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through /// the collection. /// public IEnumerator GetEnumerator() { return _source != null ? _source.GetEnumerator() : System.Linq.Enumerable.Empty().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. /// 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; } } /// /// An event handler that is invoked when the /// instance's event is /// raised. /// /// The sender of the event. /// The arguments containing the removed items. void OnSourceItemsAdded(object sender, ItemsEventArgs e) { if (ItemsAdded != null) ItemsAdded(this, e); } /// /// An event handler that is invoked when the /// instance's event is /// raised. /// /// The sender of the event. /// The arguments containing the removed items. void OnSourceItemsRemoved(object sender, ItemsEventArgs e) { if (ItemsRemoved != null) ItemsRemoved(this, e); } /// /// The backing field to . /// IEventEnumerable _source; /// /// The backing field to . /// EventHandler _itemsAdded; /// /// The backing field to . /// EventHandler _itemsRemoved; } /// /// Utility methods that make use of . /// public static class SourceEventEnumerable { /// /// Returns an that represents the /// contained in /// regardless of whether it actually exists (i.e. is null) or whether /// the instance is swapped for another /// at any point. /// /// The type that is to be held in the /// . /// The type of /// contained within /// . /// The instance whose value is to be represented /// regardless of what value it is at any given point. /// The that represents the /// value contained within . public static IEventEnumerable AsEventEnumerable(this IValue value) where TEventEnumerable : IEventEnumerable { SourceEventEnumerable sourceEventEnumerable = new SourceEventEnumerable(); value.Provide += (sender, e) => sourceEventEnumerable.Source = e.NewValue; return sourceEventEnumerable; } /// /// Performs the same task as /// /// except this method is for instances deriving from /// which are often used for collections of services in Chernobyl. /// /// The type of /// contained within /// . This type must inherit from /// with as its type. /// The instance whose value is to be represented /// regardless of what value it is at any given point. /// The that represents the /// value contained within . public static IEventEnumerable AsServices(this IValue value) where TEventEnumerable : IEventEnumerable { return value.AsEventEnumerable(); } } }