Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using generics in a Parent Child relationship

Tags:

c#

generics

I have an abstract class BaseItem declared like this:

public abstract class BaseItem
{
    public BaseItem Parent { get; protected set; }
    public List<BaseItem> Children = new List<BaseItem>();

    public abstract string Function1();        
}

Basically, i'm trying to implement a design where each Item has a parent that will be of one specific type and children that will be of a different type.

For example, ItemA would have children all of ItemB type. Then ItemB would have a parent of ItemA type and children all of ItemC type. ItemC would have parent of ItemB and children of ItemD type.

I thought it would be neater to do this using generics to avoid unnecessary casts since i know what type the parent and children will be for each of my inherited classes. So i came up with something like this:

public abstract class AbstractBase
{
    public abstract string Function1();
}

public abstract class BaseItem<T1, T2> : AbstractBase
    where T1 : AbstractBase
    where T2 : AbstractBase
{
    public T1 Parent { get; protected set; }
    public List<T2> Children = new List<T2>();
}

public class ItemA : BaseItem<ItemA, ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : BaseItem<ItemC, ItemD>
{
}

So two things. 1. Is this a good design? Is there a simpler/better way of doing this? I don't really like using a second abstract base class just to be able to use generics. 2. If i do keep this, what's the best way of handling the ends? (i.e ItemA does not have a parent in my actual problem domain, but it needs a parent to compile. ItemD does not have children, but i need to give it something)

like image 744
David A. Avatar asked Aug 02 '10 15:08

David A.


People also ask

Can generic types be inherited?

Generic classes support an inheritance mechanism and can form hierarchies. Any generic class that takes a type T as a parameter can be inherited by another derived class. In this case, a parameter of type T is passed to the derived class.

What is parent/child relationship theory?

A form of filial therapy, child-parent relationship theory (CPRT) teaches parents to use child-centered play therapy (CCPT) skills with their children. Based on attachment theory, CPRT espouses that a secure bond between parent and child is mandatory for children's healthy development.

What is parent and child relationship with example?

The Parent-Child Relationship is one that nurtures the physical, emotional and social development of the child. It is a unique bond that every child and parent will can enjoy and nurture. This relationship lays the foundation for the child's personality, life choices and overall behaviour.

What are parent/child relationships called?

Also known as a document family.


2 Answers

If I understand you right, you are saying that ItemA never has a parent and ItemD never has any children, right? To be honest, I would probably just declare the separate classes with their own parent/children properties of the right type:

public abstract class AbstractBase
{
    public abstract string Function1();
}

public class ItemA : AbstractBase
{
    public List<ItemB> Children = new List<ItemB>();
}
public class ItemB : AbstractBase
{
    public ItemA Parent { get; protected set; }
    public List<ItemC> Children = new List<ItemC>();
}
public class ItemC : AbstractBase
{
    public ItemB Parent { get; protected set; }
    public List<ItemD> Children = new List<ItemD>();
}
public class ItemD : AbstractBase
{
    public ItemC Parent { get; protected set; }
}

The only thing you are repeating here is the Parent and Children property/field. All the other common functionality you can implement in the AbstractBase. (Unless, of course, that functionality needs access to the parents/children — but then you’re back to square one even in your solution.)

like image 91
Timwi Avatar answered Nov 07 '22 22:11

Timwi


I would do it like this:

public interface IChildOf<T> {
    T Parent { get;  set; }
}

public interface IParent<T> {
    List<T> Children { get; set; }
}

//This class handles all of the cases that have both parent and children
public abstract class BaseItem<T1, T2> : IParent<T1>, IChildOf<T2>
{
    public List<T1> Children { get; set; }
    public T2 Parent { get; set; }
}

//This class handles the top level parent
public class ItemA : IParent<ItemB>
{
    public List<ItemB> Children { get;  set; }
}
public class ItemB : BaseItem<ItemC, ItemA>
{
}
public class ItemC : BaseItem<ItemD, ItemB>
{
}
//.... as many intermediates as you like.

//This class handles the bottom level items with no children
public class ItemD : IChildOf<ItemC>
{
    public ItemC Parent { get;  set; }
}
like image 37
Daniel Dyson Avatar answered Nov 07 '22 22:11

Daniel Dyson