using System.Collections; using System.Collections.Generic; using System.Linq; using Chernobyl.Collections.Generic; using Chernobyl.Collections.Generic.Event; using Chernobyl.Collections.Generic.Hierarchy; using Chernobyl.Event; namespace Chernobyl.Reflection.Template { /// /// An interface for dealing with objects that are part or piece of some /// coding construct. For example, instances, variables, properties, methods, /// arguments to a method, etc are all components. /// public interface IComponent : INamed, ITreeEnumerable { /// /// The namespace or prefix of this component. /// string Prefix { get; } /// /// The name of this component which can be used to generate code for /// this component. /// string CodeName { get; } /// /// The that is the parent to this /// . This will be /// added to the parent 's /// list. If this /// is already a child to another then it will /// be removed from that 's /// list. Setting null on this property /// will cause this to be removed from it's /// parent, if necessary. /// IComponent Parent { get; set; } /// /// Sub-components of this which may include /// members, arguments, attributes, or other data depending on the goals /// of the implementing type. /// IEventCollection ComponentChildren { get; } /// /// The that "decorates" /// (http://en.wikipedia.org/wiki/Decorator_pattern) this /// . The decorator is used when this /// needs client code to refer to the /// decorator rather than this such as when /// parenting children. In the event that a decorator doesn't exist, /// this property is set to null. /// IComponent Decorator { get; set; } } /// /// An implementation of to make the creation of /// new types easier. /// public abstract class Component : IComponent { /// /// Initializes a new instance of the class. /// /// The services instance to use when injecting /// or receiving dependencies from created instances. /// The namespace or prefix of this component. /// The name of this component which can be used to generate code for /// this component. protected Component(IEventCollection services, string prefix, string name) { Services = services; _prefix = prefix; Name = name; ComponentChildren = new DecoratingEventCollection(new List()); ComponentChildren.ItemsAdded += OnComponentChildrenAdded; ComponentChildren.ItemsRemoved += OnComponentChildrenRemoved; } /// /// The that is the parent to this /// . This will be /// added to the parent 's /// list. If this /// is already a child to another then it will /// be removed from that 's /// list. Setting null on this property /// will cause this to be removed from it's /// parent, if necessary. /// public virtual IComponent Parent { get { return _parent; } set { if (_parent != value) { IComponent child = Decorator ?? this; // remove from the previous parent, if necessary if (_parent != null) _parent.ComponentChildren.Remove(child); _parent = value; // only add to this new parent's list if it is actually a // parent and we aren't already in its children list. if (value != null && value.ComponentChildren.Contains(child) == false) _parent.ComponentChildren.Add(child); } } } /// /// The namespace or prefix of this component. /// public virtual string Prefix { get { return _prefix; } protected set { _prefix = value; } } /// /// The name of this component which can be used to generate code for /// this component. /// public abstract string CodeName { get; } /// /// Sub-components of this which may include /// members, arguments, attributes, or other data depending on the goals /// of the implementing type. /// public IEventCollection ComponentChildren { get; protected set; } /// /// Gets or sets the name of the instance. /// public string Name { get; set; } /// /// An that iterates over an /// in depth first order (see /// http://en.wikipedia.org/wiki/Depth-first_search for more information). /// public IEnumerable DepthFirst { get { return new EnumeratorFactory( () => new DepthFirstEnumerator(this, item => item.ComponentChildren.GetEnumerator())); } } /// /// An that iterates over an /// in breadth first order (see /// http://en.wikipedia.org/wiki/Breadth-first_search for more information). /// public IEnumerable BreadthFirst { get { return new EnumeratorFactory( () => new BreadthFirstEnumerator(this, item => item.ComponentChildren.GetEnumerator())); } } /// /// Returns an enumerator that iterates through this /// and the tree /// underneath it. /// /// /// A that can /// be used to iterate through the tree. /// public IEnumerator GetEnumerator() { return BreadthFirst.GetEnumerator(); } /// /// Returns an that iterates through this /// and the tree /// underneath it. /// /// /// A that can /// be used to iterate through the tree. /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// The that "decorates" /// (http://en.wikipedia.org/wiki/Decorator_pattern) this /// . The decorator is used when this /// needs client code to refer to the /// decorator rather than this such as when /// parenting children. In the event that a decorator doesn't exist, /// this property is set to null. /// public IComponent Decorator { get { return _decorator; } set { if(_decorator != value) { // we have a new decorator so we'll have to make it our // children's parent _decorator = value; // note that, when you set the parent of a child, it may get // removed from this IComponents ComponentChildren collection. // Below we convert the ComponentChildren children to an // array so as to prevent exceptions when the child list // gets modified after the new parent is set on the children. IComponent newParent = _decorator ?? this; foreach (IComponent child in ComponentChildren.ToArray()) child.Parent = newParent; } } } /// /// A method that is invoked right after children /// have been added to this as a child. In that /// event, the children's s are set to the /// of this instance. /// /// The instance that generated the event. /// The instance /// containing the event data. protected virtual void OnComponentChildrenAdded(object sender, ItemsEventArgs e) { foreach (IComponent child in e.Items) child.Parent = Decorator ?? this; } /// /// A method that is invoked right after children /// have been removed from this 's /// list. In that event, the children's /// s are set to null. /// /// The instance that generated the event. /// The instance /// containing the event data. protected virtual void OnComponentChildrenRemoved(object sender, ItemsEventArgs e) { foreach (IComponent child in e.Items) child.Parent = null; } /// /// The services instance to use when injecting or receiving /// dependencies from created instances. /// protected IEventCollection Services { get; private set; } /// /// The backing field to . /// // ReSharper disable InconsistentNaming protected string _prefix { get; set; } // ReSharper restore InconsistentNaming /// /// The backing field to . /// IComponent _parent; /// /// The backing field to . /// IComponent _decorator; } }