5
\$\begingroup\$

I have to implement a class with has parent and child fields. The problem is that by adding a child it must immediately keep reference to its' parent. I implemented it and it seems to work but I am not quite sure if I did it right. Any advice will be useful!

namespace DocumentToDocument
{
  public class MyEventArgs<T>: EventArgs
  {
    public T D;
  }

  public class MyList<T> : List<T>
  {
    public event EventHandler OnAdd;

    public new void Add(T item)
    {
      if (null != OnAdd)
      {
        var m = new MyEventArgs<Document> {D = item as Document};

        OnAdd(this, m);
      }
      base.Add(item);
    }
   }

   public class Document
   {
     public Document()
     {
       Children = new MyList<Document>();
       Children.OnAdd += new EventHandler(Children_OnAdd);
     }

     public string Name;

     public Document Parent;

     public MyList<Document> Children;

     public void Children_OnAdd(object sender, EventArgs e)
     {
      ((MyEventArgs<Document>) e).D.Parent = this;
     }
   }

   class Program
   {
     private static void Main(string[] args)
     {
       var d = new Document {Name = "I am a parent"};

       var dd = new Document {Name = "I am a child"};

       d.Children.Add(dd);
     }
   }
 }
\$\endgroup\$
5
  • \$\begingroup\$ I can't test it right now, but I think this will only work as long as the list of children is explicitly referenced as MyList<> - when used as List<> or IList<> the original implementation of Add() would come to bear. This violates the Liskov Substitution Principle and would cause problems when using any LINQ extension methods that may use Add(). \$\endgroup\$ Commented Mar 3, 2013 at 15:08
  • \$\begingroup\$ Good answer, GCATNM. But I have no idea how to implement this event with List<> as this datatype has no built-in OnAdd Event \$\endgroup\$
    – Micha
    Commented Mar 3, 2013 at 15:18
  • 1
    \$\begingroup\$ Micha, have you thought about implementing IList instead of inheriting List? You could keep using List as your underlying storage implementation. \$\endgroup\$ Commented Mar 3, 2013 at 15:59
  • \$\begingroup\$ Yes, I implemented IList. Seems more mature ) \$\endgroup\$
    – Micha
    Commented Mar 3, 2013 at 20:12
  • \$\begingroup\$ It's certainly a much cleaner way. Replacing members with new is hardly ever a good solution, and particularly so in this case, as what you actually want is an override, but new can't give you that. \$\endgroup\$ Commented Mar 3, 2013 at 22:39

1 Answer 1

1
\$\begingroup\$

Here's how I might restructure it (note, I've removed many of the generics since it seems to be tied to Document - if you do need those classes to go for other types, go back to the generics, otherwise, YAGNI):

namespace DocumentToDocument
{
    using System;
    using System.Collections.Generic;

    public sealed class MyEventArgs : EventArgs
    {
        private readonly Document document;

        public MyEventArgs(Document document)
        {
            this.document = document;
        }

        public Document Document
        {
            get
            {
                return this.document;
            }
        }
    }

    public sealed class MyList : List<Document>
    {
        public event EventHandler<MyEventArgs> OnAdd;

        public new void Add(Document item)
        {
            var onAdd = this.OnAdd;

            if (onAdd != null)
            {
                onAdd(this, new MyEventArgs(item));
            }

            base.Add(item);
        }
    }

    public sealed class Document
    {
        private readonly MyList children = new MyList();

        private readonly string name;

        private Document parent;

        public Document(string name, Document parent = null)
        {
            this.name = name;
            this.parent = parent;
            if (this.parent != null)
            {
                this.parent.Children.Add(this);
            }

            this.children.OnAdd += (sender, e) => e.Document.Parent = this;
        }

        public string Name
        {
            get
            {
                return this.name;
            }
        }

        public Document Parent
        {
            get
            {
                return this.parent;
            }

            set
            {
                this.parent = value;
            }
        }

        public MyList Children
        {
            get
            {
                return this.children;
            }
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            var d = new Document("I am a parent");
            var dd = new Document("I am a child", d);
        }
    }
}
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.