This seems like a really basic problem, but I'm struggeling to find an elegant solution. I have a Node class that I'm using to build a tree structure. This is then serialized to JSON using JsonConvert.SerializeObject(..). In order to prevent circular references when serializing, I've placed a JsonIgnore attribute on the Parent property.
This obviously means that the parent is not being serialized as part of each node in the resulting JSON output.
When I deserialize the same JSON string, I want the Node objects to have the proper Parent assigned so that I can easily traverse the tree upwards. What is the cleanest and simplest way of achieving this?
[JsonObject]
public class Node : IEnumerable<Node>
{
public Guid Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
public Node Parent { get; private set; }
[JsonProperty("Children")]
private readonly Dictionary<Guid, Node> _children = new Dictionary<Guid, Node>();
public Node()
{
Id = Guid.NewGuid();
}
public void Add(Node departmentNode)
{
if (node.Parent != null)
{
node.Parent._children.Remove(node.Id);
}
node.Parent = this;
_children.Add(node.Id, node);
}
public IEnumerator<Node> GetEnumerator()
{
return _children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You could get rid of the Parent altogether and use something like FindParent(node.Id) when you need to find it.
If this not feasible (it should be though) and you need to have a parent reference my suggestion would be to go through the tree and set the parent references after you deserialize.
What I did to solve it was to ignore the serialization of the Parent and implement a public property called Children which sets my private ChildrenDict collection. When I add the children to the private dictionary, I also set the Parent property of each child.
Personally, I don't like to pollute my data classes with JSON-specific attributes, because I like to have a serializer independent clean design.
Said so, the end solution doesn't use JsonIgnoreAttribute tags and defines:
a private parameterless constructor, used by JSON deserializer
a private Parent property (ignored by JSON serializer)
a public GetParent() method (for your own use)
a public constructor taking parent as argument (for your own use)
One could also define a SetParent() method, although in my code I didn't need it at all.
This code was tested with NewtonsoftJson serialization & DotNET 4.5.2
using System.Collections.Generic;
using System.Linq;
namespace JsonSerializableNode
{
public class Node
{
private Node() { } // used for deserializing
public Node(string name, Node parent) // used everywhere else in your code
{
Name = name;
Parent = parent;
}
public string Name { get; set; }
private Node Parent { get; set; }
public Node GetParent()
{
return Parent;
}
public Node[] Children
{
get
{
return ChildrenDict.Values.ToArray();
}
set
{
ChildrenDict.Clear();
if (value == null || value.Count <= 0) return;
foreach (Node child in value)
Add(child);
}
}
// One could use a typed OrderedDictionary here, since Json lists guarantee the order of the children:
private Dictionary<string, Node> ChildrenDict { get; } = new Dictionary<string, Node>();
public Node Add(Node child)
{
ChildrenDict.Add(child.Name, child);
child.Parent = this;
return child;
}
public Node Get(string name)
{
return ChildrenDict[name];
}
public bool Remove(string name)
{
return ChildrenDict.Remove(name);
}
}
}
Related
Given the following over-simplified code:
public class Child
{
public virtual Parent Parent { get; set; }
}
public class Parent
{
public List<Child> Children { get; set; }
}
In my consumer code, I'd have:
parent.Children.Add(child);
This does not set the child.Parent, until I call db.SaveContext();
I see situations in which this is a problem, e.g. chaining a couple of operations on the same object before saving.
My question is, should I be doing this instead:
class Child
{
public virtual Parent Parent { get; set; }
public void SetParent(Parent parent) {
if (this.Parent != null) { this.Parent.Children.Remove(this); }
parent.Children.Add(this);
this.Parent = parent;
}
}
Please note the code snippet is just for illustrative purpose.
Generally my question is, should I handle the relational fix up myself, instead of relying on EF.
For simplicity, I would try to avoid the kind of chained operations that would require you to have to do this, but I don't think there is anything wrong with doing it if you need it.
A suggestion: Do not directly expose the Children collection in your Parent class, make its setter method private or protected, and add methods to add and remove Children elements in the Parent class. This is the way to ensure that the logic to set Child parent is always executed whenever the collection changes.
public class Parent
{
public List<Child> Children { get; protected set; }
public void AddChild(Child child)
{
Children.Add(child);
child.Parent = this;
}
public void RemoveChild(Child child)
{
Children.Remove(child);
child.Parent = null;
}
}
I have create a generic Node class which will be used to build a tree object. I want to inherit the attributes of this class in another. The job class represents a SQL job which is included in a chain (tree) of jobs. The following code is giving me an error and I am not sure why.
public class Node<T>
{
public int id { get; set; }
public Node<T> parent { get; set; }
public List<Node<T>> Children = new List<Node<T>>();
public bool isRoot
{
get { return parent == null; }
}
public static Node<T> createTree(List<Node<T>> nodes)
{
if (nodes.Count() == 0)
return new Node<T>();
//Build parent / Child relationships
}
}
public class Job : Node<Job>
{
public string name {get; set;}
public Job(String name)
{
this.name = name;
}
}
List<Job> joblist = JobDict.Select(j => new Job(j.Key)).ToList();
Node<Job>.createTree(joblist);
I am Unable to call createTree with the List of Jobs. I realize changing it from List < Job > to List < Node< Job > > works but why am I unable to do the former? I figured because I am inheriting the node class, a List of Jobs would in fact be equivalent to a List of Node. I am sorry if this is a very basic question but I just began with generics and inheritance and am having a hard time grasping it entirely.
The problem is that List<Node<Job>> and List<Job> are not co-variant.
If you're using .NET 4 you can do this.
Node<Job>.createTree((IEnumerable<Node<Job>>)joblist);
or, you can modify the creeatetree method definition as follows.
public static Node<T> createTree(IList nodes)
{
if (nodes.Count == 0)
return new Node<T>();
//Build parent / Child relationships
}
I realize changing it from List<Job> to List<Node<Job>> works
but why am I unable to do the former?
Because List<Job> does not inherit List<Node<Job>> even if Job inherits Node<Job>. In other words, A inherits B does not mean List<A> inherits List<B>.
You may need to cast each Job object to Node<Job> first:
var jobNodeList = joblist.Select(j => (Node<Job>)j).ToList();
Node<Job>.createTree(jobNodeList);
This isn't a direct answer to the question, but it might give you some ideas on how to make your code simpler.
It's often a good idea to keep code simple. The simplest tree structure you can make is this:
public class Tree<T> : List<Tree<T>> { }
In your case, you would extend it slightly as:
public class Node<T> : List<Node<T>>
{
public int id { get; set; }
public Node<T> parent { get; set; }
public bool isRoot
{
get { return parent == null; }
}
}
Effectively you get all of the Children properties for free.
I have a class that contains an IList<T> property called Children. Each child should reference its parent. My solution has been to set the ChildClass.Parent property in the ParentClass.Children getter. Is there a better way, or is this the best solution?
class ParentClass
{
private IList<ChildClass> _children;
public virtual IList<ChildClass> Children
{
get
{
// make sure each child refers to its parent (this)
foreach (ChildClass c in _children)
{
c.Parent = c.Parent ?? this;
}
return _children;
}
set
{
_children = value;
}
}
}
It could just be me...but this looks like a bad design.
If it's a true Parent -> Child relationship, you shouldn't allow anybody to create an Orphan Child. Therefore, the Parent should be set on the Child at the time of creation.
I would probably do something like:
class ChildClass
{
private ParentClass _parent;
public ChildClass(ParentClass parent)
{
_parent = parent;
}
}
And then:
class ParentClass
{
private List<ChildClass> _children;
public virtual ReadOnlyCollection<ChildClass> Children
{
get
{
return _children.AsReadOnly();
}
}
public virtual ChildClass CreateChild()
{
// Set parent in child class constructor
ChildClass newChild = new ChildClass(this);
_children.Add(newChild);
return newChild;
}
}
The problem with your solution is that if all the children and parents are correctly linked, your code will re-link them each time the internal child collection is retrieved. Also, it seems that this problem exists because you are returning a reference to a private collection, after which you lose control of the elements it contains.
I suggest the following:
Provide Add(ChildCLass) and Remove(ChildClass) methods on ParentClass, and enforce the parent-child constraint there. This allows children to be created anywhere, and be linked correctly when belonging to the hierarchy. When the are removed from the hierarchy, the are no longer linked.
Do not return a reference to your internal ChildClass collection unless the collection is immutable. Returning a ReadOnlyCollection or IEnumerable is preferable.
Examples:
class ChildClass
{
// Prevent unauthorized clients from overriding the Parent reference.
public ParentClass Parent { get; internal set; }
// ... other methods and properties ...
}
class ParentClass
{
private IList<ChildClass> _children;
public void AddChild(ChildClass child)
{
_children.Add(child);
child.Parent = this;
}
public RemoveChild(ChildClass child)
{
_children.Remove(child);
child.Parent = null;
}
public IList<ChildClass> Children
{
get { return _children.AsReadOnly(); }
}
}
I've a question regarding enforcing a business rule via a specification pattern. Consider the following example:
public class Parent
{
private ICollection<Child> children;
public ReadOnlyCollection Children { get; }
public void AddChild(Child child)
{
child.Parent = this;
children.Add(child);
}
}
public class Child
{
internal Parent Parent
{
get;
set;
}
public DateTime ValidFrom;
public DateTime ValidTo;
public Child()
{
}
}
The business rule should enforce that there cannot be a child in the collection which validity period intersects with another.
For that I would like to implement a specification that is then be used to throw an exception if an invalid child is added AND as well can be used to check whether the rule will be violated BEFORE adding the child.
Like:
public class ChildValiditySpecification
{
bool IsSatisfiedBy(Child child)
{
return child.Parent.Children.Where(<validityIntersectsCondition here>).Count > 0;
}
}
But in this example the child accesses the parent. And to me that doesnt seem that correct. That parent might not exist when the child has not been added to the parent yet. How would you implement it?
public class Parent {
private List<Child> children;
public ICollection<Child> Children {
get { return children.AsReadOnly(); }
}
public void AddChild(Child child) {
if (!child.IsSatisfiedBy(this)) throw new Exception();
child.Parent = this;
children.Add(child);
}
}
public class Child {
internal Parent Parent { get; set; }
public DateTime ValidFrom;
public DateTime ValidTo;
public bool IsSatisfiedBy(Parent parent) { // can also be used before calling parent.AddChild
return parent.Children.All(c => !Overlaps(c));
}
bool Overlaps(Child c) {
return ValidFrom <= c.ValidTo && c.ValidFrom <= ValidTo;
}
}
UPDATE:
But of course, the real power of the specification pattern is when you can plug in and combine different rules. You can have an interface like this (possibly with a better name):
public interface ISpecification {
bool IsSatisfiedBy(Parent parent, Child candidate);
}
And then use it like this on Parent:
public class Parent {
List<Child> children = new List<Child>();
ISpecification childValiditySpec;
public Parent(ISpecification childValiditySpec) {
this.childValiditySpec = childValiditySpec;
}
public ICollection<Child> Children {
get { return children.AsReadOnly(); }
}
public bool IsSatisfiedBy(Child child) {
return childValiditySpec.IsSatisfiedBy(this, child);
}
public void AddChild(Child child) {
if (!IsSatisfiedBy(child)) throw new Exception();
child.Parent = this;
children.Add(child);
}
}
Child would be simple:
public class Child {
internal Parent Parent { get; set; }
public DateTime ValidFrom;
public DateTime ValidTo;
}
And you could implement multiple specifications, or composite specifications. This is the one from your example:
public class NonOverlappingChildSpec : ISpecification {
public bool IsSatisfiedBy(Parent parent, Child candidate) {
return parent.Children.All(child => !Overlaps(child, candidate));
}
bool Overlaps(Child c1, Child c2) {
return c1.ValidFrom <= c2.ValidTo && c2.ValidFrom <= c1.ValidTo;
}
}
Note that it makes more sense to make Child's public data immutable (only set through the constructor) so that no instance can have its data changed in a way that would invalidate a Parent.
Also, consider encapsulating the date range in a specialized abstraction.
I think the Parent should probably do the validation. So in the parent you might have a canBeParentOf(Child) method. This method would also be called at the top of your AddChild method--then the addChild method throws an exception if canBeParentOf fails, but canBeParentOf itself does not throw an exception.
Now, if you want to use "Validator" classes to implement canBeParentOf, that would be fantastic. You might have a method like validator.validateRelationship(Parent, Child). Then any parent could hold a collection of validators so that there could be multiple conditions preventing a parent/child relationship. canBeParentOf would just iterate over the validators calling each one for the child being added--as in validator.canBeParentOf(this, child);--any false would cause canBeParentOf to return a false.
If the conditions for validating are always the same for every possible parent/child, then they can either be coded directly into canBeParentOf, or the validators collection can be static.
An aside: The back-link from child to parent should probably be changed so that it can only be set once (a second call to the set throws an exception). This will A) Prevent your child from getting into an invalid state after it's been added and B) detect an attempt to add it to two different parents. In other words: Make your objects as close to immutable as possible. (Unless changing it to different parents is possible). Adding a child to multiple parents is obviously not possible (from your data model)
Would you not have an If statement to check that a parent was not null and if so return false?
You are trying to guard against Child being in an invalid state. Either
use the builder pattern to create fully populated Parent types so that everything you expose to the consumer is always in a valid state
remove the reference to the Parent completely
have Parent create all instances of Child so this can never occur
The latter case might look (something) like this (in Java):
public class DateRangeHolder {
private final NavigableSet<DateRange> ranges = new TreeSet<DateRange>();
public void add(Date from, Date to) {
DateRange range = new DateRange(this, from, to);
if (ranges.contains(range)) throw new IllegalArgumentException();
DateRange lower = ranges.lower(range);
validate(range, lower);
validate(range, ranges.higher(lower == null ? range : lower));
ranges.add(range);
}
private void validate(DateRange range, DateRange against) {
if (against != null && range.intersects(against)) {
throw new IllegalArgumentException();
}
}
public static class DateRange implements Comparable<DateRange> {
// implementation elided
}
}
I'm finding it difficult to find a decent example on how to implement a parent-child hierarchy class.
I have a treeView control that I want to convert into a class hierarchy, adding extra data to each node and be able to easely iterate over each parent's nodes using IEnumerable.
public IEnumerable<Node> GetAllChildsFromParent(Node parent)
{
foreach (Node node in parent.NodeChildsCollection)
{
yield return node;
}
}
I already have implemented the following piece of code but got stuck and don't really
have a clue whether I am on the right track or not? How should I proceed to complete this ?
public class NodeChildsCollection : IEnumerable<Node>
{
IList<Node> nodeCollection = new List<Node>();
Node parent;
public Node Parent
{
get { return parent; }
set { parent = value; }
}
public NodeChildsCollection()
{
}
public void AddNode(Node parent, Node child)
{
this.parent = parent;
nodeCollection.Add(child);
}
#region IEnumerable<Node> Members
public IEnumerator<Node> GetEnumerator()
{
foreach (Node node in nodeCollection)
{
yield return node;
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
public class Node
{
NodeChildsCollection nodeChildsCollection = new NodeChildsCollection();
public Node Parent
{
get { return nodeChildsCollection.Parent; }
set { nodeChildsCollection.Parent = value; }
}
public void AddChild(Node child)
{
nodeChildsCollection.AddNode(this, child);
}
}
You're mixing the responsibilities of the Node with the responsibilities of the collection. See how you're setting the parent in the collection? It's not the collection that has a parent; its the node.
I'd structure my nodes like thus:
public class Node
{
public Node Parent {get;set;} // null for roots
public NodeCollection Children {get; private set;}
public Node()
{
Children = new NodeCollection();
Children.ChildAdded += ChildAdded;
Children.ChildRemoved += ChildRemoved;
};
private void ChildAdded(object sender, NodeEvent args)
{
if(args.Child.Parent != null)
throw new ParentNotDeadYetAdoptionException("Child already has parent");
args.Child.Parent = this;
}
private void ChildRemoved(object sender, NodeEvent args)
{
args.Child.Parent = null;
}
}
And the NodeCollection would look like
public class NodeCollection : INodeCollection {/*...*/}
and INodeCollection would be:
public interface INodeColleciton : IList<Node>
{
event EventHandler<NodeEvent> ChildAdded;
event EventHandler<NodeEvent> ChildRemoved;
}
The collection responsibilities are on the Child collection property of the Node. You can, of course, have node implement INodeCollection, but that's a matter of programming tastes. I prefer to have the Children public property (its how the framework is designed).
With this implementation you don't need to implement a "GetChildren" method; the public Children property provides them for all.
I found the this blog article quite useful when attempting to solve the same problem.
If you want to separate the notion of a tree-like data structure from the specific data being stored, make it a general purpose container by making it generic.
Also, if the tree has a single root, a treenode is itself a collection of treenodes, so (like any collection) the method for adding an item should be called Add. Making the child collection a separate object would only make sense if you often have collections of trees. This occurs in TreeViews in the Windows UI because the root of a TreeView contains multiple nodes rather than a single root treenode. However, in something like the XML or HTML DOM, there's always a single root, and so I think something simpler is appropriate.
Finally, you don't need to implement the IEnumerable stuff with yield return - just forward to a standard container's implementation.
public class TreeNode<TValue> : IEnumerable<TreeNode<TValue>>
{
private List<TreeNode<TValue>> _children = new List<TreeNode<TValue>>();
public TreeNode<TValue> Parent { get; private set; }
public void Add(TreeNode<TValue> child)
{
_children.Add(child);
child.Parent = this;
}
public void Remove(TreeNode<TValue> child)
{
_children.Remove(child);
child.Parent = null;
}
public IEnumerator<TreeNode<TValue>> GetEnumerator()
{
return _children.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _children.GetEnumerator();
}
}
In fact you could make it implement IList<TreeNode<TValue>> and forward all the methods on to the list, with appropriate manipulation of the Parent property whenever adding/removing children.