473,387 Members | 1,530 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Code Review! Parent-child relationships

Hi all,

I've been trying to write some classes, so when I have a parent-child
relationship, such as with Folders in my application, I don't have to
remember to add a parent reference, as well as adding to the child
collection, eg:

parent.Children.Add(child);
child.Parent = parent;

And I've come up with the below (I've included my test, and three classes).
It seems to work, but I have two questions....

1. Does this look like the best way of doing this?

2. I now want to extend this to support multiple lists (eg, my folders can
contain both folders, and messages. Messages can have child messages, and
therefore have both a parent folder, and a parent message), eg.

folder.ChildFolders // Returns List<TreeItem<Folder>>
folder.Messages // Returns List<TreeItem<Message>>

message.ParentMessage // Returns TreeItem<Message>
message.ParentFolder // Returns TreeItem<Folder>

Or should I create a base class that represents the entire tree (Folders and
Messages)? Though this way, I'd have a single child list, and would need to
add properties, like .ChildFolders, which would filter the .Children list!

I know it looks like a lot of code here, but it's just 3 classes and my
command line test. If you paste it into VS, it'll look dead simple :)

Any thoughts or suggestions?

Thanks,

Danny Tuppeny

namespace MyApplication
{
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
}

static void Test1()
{
Folder parent = new Folder();
Folder child = new Folder();

child.Parent = parent;

if (parent.Children.Contains(child))
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}

static void Test2()
{
Folder parent = new Folder();
Folder child = new Folder();

parent.Children.Add(child);

if (parent == child.Parent)
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}
}

public class ChildList<T> : List<T>
{
public event EventHandler<ChildListEventArgs<T>> Added;
public event EventHandler<ChildListEventArgs<T>> Removed;

public class ChildListEventArgs<T> : EventArgs
{
public T Item;
public ChildListEventArgs(T item)
{
Item = item;
}
}

public new void Add(T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));

base.Add(item);
}

public new void AddRange(IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}

base.AddRange(collection);
}

public new void Insert(int index, T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));

base.Insert(index, item);
}

public new void InsertRange(int index, IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}

base.InsertRange(index, collection);
}

public new bool Remove(T item)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(item));

return base.Remove(item);
}

public new void RemoveAll(Predicate<T> match)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.FindAll(match))
{
removed(this, new ChildListEventArgs<T>(item));
}
}

base.RemoveAll(match);
}

public new void RemoveAt(int index)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(base[index]));

base.RemoveAt(index);
}

new void RemoveRange(int index, int count)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.GetRange(index, count))
{
removed(this, new ChildListEventArgs<T>(item));
}
}

base.RemoveAt(index);
}
}

public class TreeItem<T>
{
TreeItem<T> parent;
ChildList<TreeItem<T>> children;

public TreeItem()
{
children = new ChildList<TreeItem<T>>();
children.Added += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent =
this; };
children.Removed += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent =
null; };
}

public TreeItem<T> Parent
{
get { return parent; }
set
{
if (parent != value)
{
if (parent != null)
{
// This automagically unsets the internal parent
parent.children.Remove(this);
}
if (value != null)
{
// This automagically sets the internal parent
value.children.Add(this);
}
}
}
}

public ChildList<TreeItem<T>> Children
{
get { return children; }
}
}

public class Folder : TreeItem<Folder>
{
string name;

public Folder()
{
}

public string Name
{
get { return name; }
set { name = value; }
}

}
}
Nov 17 '05 #1
4 4533
um... HOw 'bout a nice simple:

parent.AddChild(child);

where AddChild is defined as

public AddChild(IChild pChild)
{
this.Children.Add(child);
child.Parent = this;
}

--
Truth,
James Curran
[erstwhile VC++ MVP]

Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Danny Tuppeny" <gr****@dannytuppeny.commmmmm> wrote in message
news:43***********************@ptn-nntp-reader04.plus.net...
Hi all,

I've been trying to write some classes, so when I have a parent-child
relationship, such as with Folders in my application, I don't have to
remember to add a parent reference, as well as adding to the child
collection, eg:

parent.Children.Add(child);
child.Parent = parent;

And I've come up with the below (I've included my test, and three classes). It seems to work, but I have two questions....

1. Does this look like the best way of doing this?

2. I now want to extend this to support multiple lists (eg, my folders can
contain both folders, and messages. Messages can have child messages, and
therefore have both a parent folder, and a parent message), eg.

folder.ChildFolders // Returns List<TreeItem<Folder>>
folder.Messages // Returns List<TreeItem<Message>>

message.ParentMessage // Returns TreeItem<Message>
message.ParentFolder // Returns TreeItem<Folder>

Or should I create a base class that represents the entire tree (Folders and Messages)? Though this way, I'd have a single child list, and would need to add properties, like .ChildFolders, which would filter the .Children list!

I know it looks like a lot of code here, but it's just 3 classes and my
command line test. If you paste it into VS, it'll look dead simple :)

Any thoughts or suggestions?

Thanks,

Danny Tuppeny

namespace MyApplication
{
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
}

static void Test1()
{
Folder parent = new Folder();
Folder child = new Folder();

child.Parent = parent;

if (parent.Children.Contains(child))
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}

static void Test2()
{
Folder parent = new Folder();
Folder child = new Folder();

parent.Children.Add(child);

if (parent == child.Parent)
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}
}

public class ChildList<T> : List<T>
{
public event EventHandler<ChildListEventArgs<T>> Added;
public event EventHandler<ChildListEventArgs<T>> Removed;

public class ChildListEventArgs<T> : EventArgs
{
public T Item;
public ChildListEventArgs(T item)
{
Item = item;
}
}

public new void Add(T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));

base.Add(item);
}

public new void AddRange(IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}

base.AddRange(collection);
}

public new void Insert(int index, T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));

base.Insert(index, item);
}

public new void InsertRange(int index, IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}

base.InsertRange(index, collection);
}

public new bool Remove(T item)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(item));

return base.Remove(item);
}

public new void RemoveAll(Predicate<T> match)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.FindAll(match))
{
removed(this, new ChildListEventArgs<T>(item));
}
}

base.RemoveAll(match);
}

public new void RemoveAt(int index)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(base[index]));

base.RemoveAt(index);
}

new void RemoveRange(int index, int count)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.GetRange(index, count))
{
removed(this, new ChildListEventArgs<T>(item));
}
}

base.RemoveAt(index);
}
}

public class TreeItem<T>
{
TreeItem<T> parent;
ChildList<TreeItem<T>> children;

public TreeItem()
{
children = new ChildList<TreeItem<T>>();
children.Added += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent = this; };
children.Removed += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent = null; };
}

public TreeItem<T> Parent
{
get { return parent; }
set
{
if (parent != value)
{
if (parent != null)
{
// This automagically unsets the internal parent
parent.children.Remove(this);
}
if (value != null)
{
// This automagically sets the internal parent
value.children.Add(this);
}
}
}
}

public ChildList<TreeItem<T>> Children
{
get { return children; }
}
}

public class Folder : TreeItem<Folder>
{
string name;

public Folder()
{
}

public string Name
{
get { return name; }
set { name = value; }
}

}
}

Nov 18 '05 #2
"James Curran" <ja*********@mvps.org> wrote in message
news:ON**************@TK2MSFTNGP09.phx.gbl...
um... HOw 'bout a nice simple:

parent.AddChild(child);

where AddChild is defined as

public AddChild(IChild pChild)
{
this.Children.Add(child);
child.Parent = this;
}


Because that relies on remember not to use .Children.Add :)

If I can do some extra work now, which reduces the number of bugs my
software might include, it's worth it! :)

Though I guess, returning Children as a ReadOnlyList (or whatever it's
called) and then having an Add method would work.. I don't think it's as
nice though :)
Nov 18 '05 #3
OK, plan 2 (A bit stripped down, but you should get the idea)

interface IParent
{
}

interface IChild
{
IParent Parent;
}

public class ChildList<T> : List<T>
{
private IParent oOwner;
public ChildList(IParent pOwner) : base()
{
oOwner = pOwner;
}

public new void Add(T item)
{
base.Add(item);
item.Parent = oOwner;
}
}
public class Folder : IParent, IChild
{
private IParent oParent;
prinvate ChildList<Folder> children;

public Folder()
{
children = ChildList<Folder>(this);
}

}

--
Truth,
James Curran
[erstwhile VC++ MVP]

Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Danny Tuppeny" <gr****@dannytuppeny.commmmmm> wrote in message
news:43***********************@ptn-nntp-reader03.plus.net...
"James Curran" <ja*********@mvps.org> wrote in message
news:ON**************@TK2MSFTNGP09.phx.gbl...
um... HOw 'bout a nice simple:

parent.AddChild(child);

where AddChild is defined as

public AddChild(IChild pChild)
{
this.Children.Add(child);
child.Parent = this;
}


Because that relies on remember not to use .Children.Add :)

If I can do some extra work now, which reduces the number of bugs my
software might include, it's worth it! :)

Though I guess, returning Children as a ReadOnlyList (or whatever it's
called) and then having an Add method would work.. I don't think it's as
nice though :)

Nov 18 '05 #4
"James Curran" <ja*********@mvps.org> wrote in message
news:%2****************@TK2MSFTNGP14.phx.gbl...
OK, plan 2 (A bit stripped down, but you should get the idea)

<snip>

That's better - thanks :-)
Nov 18 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Volodymyr Sadovyy | last post by:
Hi. Can somebody refer me to resource with specified/analyzed/approximated productivity in Java coding and Java code review tasks? Coding productivity is more described in the net, but I didn't...
3
by: Arvie | last post by:
I need some advice guys.. I am proposing that we get someone to do a complete audit/review of our Java application codebase, about 1000 JSPs/Servlets and 100 EJBs. If I get firms to submit...
0
by: gs-code-review-bounces | last post by:
Your mail to 'gs-code-review' with the subject Re: Application Is being held until the list moderator can review it for approval. The reason it is being held: Post by non-member to a...
6
by: andrew blah | last post by:
Hello I have recently released catchmail - a free (BSD license) open source Python utility www.users.bigpond.net.au/mysite/catchmail.htm This script processes in and outbound emails and stores...
3
by: Filippo | last post by:
Hi, In my organization we would like to activate a code review system, in wich a developer have to pass a review from a reviewer before check in the modified files in source safe. Is there any way...
239
by: Eigenvector | last post by:
My question is more generic, but it involves what I consider ANSI standard C and portability. I happen to be a system admin for multiple platforms and as such a lot of the applications that my...
3
by: JeanDean | last post by:
I am looking for freeware tool which can review the c++ code(compiled on g++). Please share your experiences and details obout the usage of the tool.
10
by: Jo | last post by:
Hi there: I m wondering what can I do to improve my code, everytime I am coding I feel like it could be done better. I started on c# a good months ago and feel conformtable but sometimes I Need...
4
maxx233
by: maxx233 | last post by:
Hello all, I'm new to OO design and have a question regarding where I should place some code. Here's a simplified situation: I'm making an app to do create, submit, and track employee reviews...
0
by: corey | last post by:
Secure Bytes audit and vulnerability assessment software Secure Auditor named “Versatile tool” and earn “Five Star Ratings” in SC Magazine Group Test Secure Bytes is really pleased to share this...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.