using System; using System.Collections.Generic; using Chernobyl.Event; using Chernobyl.Utility; using Chernobyl.Values; namespace Chernobyl.Collections.Generic.Hierarchy { /// /// A type that is used to maintain a parent-child relationship between two /// types. /// /// The type that is the value held by this /// . /// The type whose parent is held by this /// . This type must be a reference type because a /// value type would not work properly with this class (since you can't access /// the child from ). public class Parent : DynamicContainer where TChild : class where TParent : class { /// /// Initializes a new instance of the class. /// /// The instance whose parent is being held by /// this. /// The method used to get the child /// from a /// type. This method will be used to add/remove the /// to/from the parent children . /// Thrown if /// or is null. public Parent(TChild child, Func> getChildren) { // Note: the value of this IValue is not provided in the constructor. // This is because getChildren could return a "Children" type. The // "Children" type will its own "getParent" method. If that method // was invoked during the constructor of this object a crash would // result because "getParent" would return null (since this parent // hasn't been constructed). child.ThrowIfNull("child"); getChildren.ThrowIfNull("getChildren"); _child = child; _getChildren = getChildren; Provide += OnProvide; } /// /// An event handler that is invoked when the parent has been changed. /// /// The sender of the event. /// The event arguments containg the old and new parent. void OnProvide(object sender, ValueChangedEventArgs e) { if (e.OldValue != null) _getChildren(e.OldValue).Remove(_child); if (e.NewValue != null) { ICollection children = _getChildren(e.NewValue); if(children.Contains(_child) == false) children.Add(_child); } } /// /// The instance whose parent is being held by this. /// readonly TChild _child; /// /// The method used to get the child from /// a type. /// readonly Func> _getChildren; } /// /// A type that is used to maintain a parent-child relationship between two /// types. This type performs the same job as /// but is easier to create for /// types. /// /// The reference type that /// makes up the types contained in the hierarchy. public class HierarchalParent : Parent where T : class, IHierarchal { /// /// Initializes a new instance of the /// class. /// /// The instance whose parent is being held by /// this. public HierarchalParent(T child) : base(child, parent => parent.Children) {} } }