I am creating a tree structure based on the AbstractNode class. The AbstractNode class has a common collection property that contains its child nodes. See the sample code below.
Is there some way, perhaps using generics, I can restrict a specific version of AbstractNode to allow only one type of child node? See the code below for ConcreteNodeA , where its ChildNodes property is a ConcreteNodeB collection, not an AbstractNode . This, of course, does not compile, but I wonder if there is another method that I could use to have the same effect.
Of course, everything will work with the ChildNodes property, always of type AbstractNode , but I'm trying to inject some logic into my classes with respect to the fact that nodes must be children of other nodes. Plus, when referring to the ChildNodes property , it would be nice if I didn’t have to drop the collection into the collection of the type that I know should be.
public abstract class AbstractNode { public abstract NodeCollection<AbstractNode> ChildNodes { get; set; } } public class ConcreteNodeA : AbstractNode { //THIS DOES NOT COMPLILE //Error 1 'ConcreteNodeA.ChildNodes': type must be 'NodeCollection<AbstractNode>' //to match overridden member 'AbstractNode.ChildNodes' public override NodeCollection<ConcreteNodeB> ChildNodes { get; set; } } public class ConcreteNodeB : AbstractNode { public override NodeCollection<AbstractNode> ChildNodes { get; set; } } public class NodeCollection<T> : BindingList<T> { //add extra events here that notify what nodes were added, removed, or changed }
Update
Ok, I think I understood what I want, but I would like to know if anyone thinks about it “badly” or “smells funny” and why. Instead of having my nodes have a ChildNodes collection property, I am thinking of making each Node an actual collection. So my tree structure will really be just a series of collections of collections. My abstract Node classes will then use various constraints for the generic type to control the types of nodes it can have.
It makes sense? Is there a reason why I do not want to do this? I have never used generics in one of my own classes, so I'm not sure if I'm missing something.
public interface INode { } public abstract class AbsNode<T> : BindingList<T>, INode where T : INode { } public abstract class AbsNodeA<T> : AbsNode<T> where T : AbsSubNodeA { } public abstract class ConcreteNodeA : AbsNodeA<AbsSubNodeA> { } public abstract class AbsSubNodeA : INode { } public class ConcreteSubNodeA :AbsSubNodeA { } public class ConcreteSubNodeB :AbsSubNodeA { }