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.
Related
I am trying to create an interface so that I can make a class recursive tree node data structure. That way, I can write generic extension methods which will deal with the generic tree traversal logic for anything which implements that interface without having to implement it in each concrete node class.
As part of this, I want to be able to make the tree node implement IEnumerable<T>, since you can iterate through the various nodes of the tree. However, I'm having issues implementing GetEnumerator() as a generic extension method due to issues with subclass types and casting.
public interface ITreeNode<out T>
where T : ITreeNode<T>, IEnumerable<ITreeNode<T>>
{
T Parent { get; }
IEnumerable<T> Children { get; }
}
public static class TreeExensions
{
public static T GetRoot<T>(this T node) where T : ITreeNode<T>, IEnumerable<ITreeNode<T>>
{
var currentNode = node;
while (currentNode.Parent != null)
{
currentNode = currentNode.Parent;
}
return currentNode;
}
// IsRoot(), IsLeaf(), GetDepth(), etc.
public static IEnumerator<T> GetEnumerator<T>(this T node) where T : ITreeNode<T>, IEnumerable<ITreeNode<T>>
{
yield return node;
foreach (var child in node.Children)
{
foreach(var descendant in child)
{
// Cannot implicity convert ITreeNode<T> to T
yield return descendant;
}
}
}
}
public class Customer : Entity, ITreeNode<Customer>
{
public Customer Parent { get; private set; }
public IEnumerable<Customer> Children { get; private set; }
}
In the example above, I'd like GetEnumerator() for a Customer object to return IEnumerator<Customer>(). However, the compiler will error because it can't ITreeNode<Customer> into Customer, even though Customer is a recursive data structure.
I've tried doing iterative and recursive versions, but I can't seem to get around this issue. Is this possible, or am I trying to do something you can't do?
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;
}
}
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);
}
}
}
I have a Person class and two inherited classes called Parent and Child. A Parent can have n Child(s) and a Child can have n Parent(s).
What is the best way in OOD to create a reference between a Parent and a Child.
Should I create a List in each class referencing the connected Parent/Child or is there a better way?
Great question. Pure many-to-many relationships are actually quite rare, and it usually helps to introduce an intermediate object to model the relationship itself. This will prove invaluable if (when!) use cases emerge which require the capture of properties regarding the relationship (e.g. whether the child/parent relationship is natural, surrogate, adoptive, etc).
So, in addition to the Person, Parent and Child entities which you've already identified, let's introduce an object called ParentChildRelationship.
An instance of ParentChildRelationship will have a reference to exactly one Parent and One Child, and both the Parent and Child classes will hold a collection of these entities.
It's a good idea to then identify the use cases you have for working with these entities, and add appropriate helper methods to maintain the inter-object references.
In the example below I've just chosen to add a public AddChild method to the parent.
public abstract class Person
{
}
public class Parent : Person
{
private HashSet<ParentChildRelationship> _children =
new HashSet<ParentChildRelationship>();
public virtual IEnumerable<ParentChildRelationship> Children
{
get { return this._children; }
}
public virtual void AddChild(Child child, RelationshipKind relationshipKind)
{
var relationship = new ParentChildRelationship()
{
Parent = this,
Child = child,
RelationshipKind = relationshipKind
};
this._children.Add(relationship);
child.AddParent(relationship);
}
}
public class Child : Person
{
private HashSet<ParentChildRelationship> _parents =
new HashSet<ParentChildRelationship>();
public virtual IEnumerable<ParentChildRelationship> Parents
{
get { return this._parents; }
}
internal virtual void AddParent(ParentChildRelationship relationship)
{
this._parents.Add(relationship);
}
}
public class ParentChildRelationship
{
public virtual Parent Parent { get; protected internal set; }
public virtual Child Child { get; protected internal set; }
public virtual RelationshipKind RelationshipKind { get; set; }
}
public enum RelationshipKind
{
Unknown,
Natural,
Adoptive,
Surrogate,
StepParent
}
public class Person
{
Person Parent { get;set; }
IList<Person> Children { get;set; }
}
Parent can be null when you do not know the parent.
Children can be null or empty when you have no children.
Since each child is a Person, it can have a Parent or its own children.
This design, by itself, is fine until you provide more detailed use case scenarios about how it will be used or persisted.
If you can limit the direction of the association to go only one way, you will save yourself a lot of trouble (but this is not always possible).
One-way relationship:
public class Parent : Person
{
public IEnumerable<Person> Children { get; }
}
If you want to have the association going the other direction as well, you can do so too:
public class Child : Person
{
public Parent Parent { get; }
}
However, now you have a circular reference that you need to maintain, and while it's possible, it's not particularly productive.
You can often keep the association as a one-way relationship by letting the children raise events instead of explicitly referencing their parent.
As JohnIdol pointed out, a child someway down the line might become a parent. In other words DON'T make Parent and Child sub-classes of Person.
class Person
{
readonly List<Person> _children = new List<Person>(),
_parents = new List<Person>();
public IEnumerable<Person> Children
{
get { return _children.AsReadOnly(); }
}
public IEnumerable<Person> Parents
{
get { return _parents.AsReadOnly(); }
}
public void AddChild(Person child)
{
_children.Add(child);
child._parents.Add(this);
}
public void AddParent(Person parent)
{
_parents.Add(parent);
parent._children.Add(this);
}
/* And so on... */
}
I would imagine that a child can also be a parent down the line (if he gets lucky ... or unlucky, depending on points of view) so I would go with something like:
IPerson
{
string Name {get; set;}
string LastName {get; set;}
// whatever else - such as sizeOfShoe, dob, etc
}
IHaveParents
{
// might wanna limit this to a fixed size
List<IPerson> Parents {get; set;}
}
IHaveChildren
{
List<IPerson> Children {get; set;}
}
IHaveSpouse
{
IPerson Spouse {get; set;}
}
public class DudeWithParentsAndChildren : IPerson, IHaveParents, IHaveChildren, IHaveSpouse
{
public void AskMoneyToParents(){throw new Exception("Implement me!");}
public void SlapChildren(){}
private void CheatOnSpouse(){}
// some other stuff that such a dude can do i.e. GoBowling
}
And you could easily extend this any way you like when new requirements come along (trust me they will).
Update:
So in your case if you only want a Child to have Parents and the other way around you'd do something like:
public class Child : IPerson, IHaveParents
{
public void AskMoneyToParents(){throw new Exception("Implement me!");}
}
public class Parent : IPerson, IHaveChildren, IHaveSpouse
{
public void SlapChildren(){}
private void CheatOnSpouse(){}
// some other stuff that such a dude can do i.e. GoBowling
}
This way if you want to have an IHaveFriends interface you can (which basically forces the implementer to expose a list of IPersons as a property named Friends). If you don't need it don't do it, but the fact that you can easily do it just adding an interface an everything else stays the same means you've got a pretty decent extensible model (not necessarily the best, you know what I mean).
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
}
}