Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How properly initialize parent and child references between two classes through constructor

Tags:

c#

.net

I have two classes. First class is Parent, which has a list of objects (Child). Each of the Child has the reference to his Parent class. Question is how to implement this reference through the constructor.

public sealed class Child
{
    public Child(string id, string name, Parent parent)
    {
        Id = id;
        Name = name;
        Parent = parent;
    }

    public Parent ParentInstance { get; private set; }
    public string Id { get; private set; }
    public string Name { get; private set; }
}

public sealed class Parent
{
    public Parent(string id, string name, IEnumerable<Child> children)
    {
        Id = id;
        Name = name;
        Children = children;
    }

    public string Id { get; private set; }
    public string Name { get; private set; }
    public IEnumerable<Child> Children { get; private set; }
}

The issue is that I have a code which parses some XML code and creates the list of Parent objects. Here is the example:

internal Parent ParseParent(XElement parentXElement)
{
    return new Parent(parentXElement.Attribute("id").Value, parentXElement.Attribute("name").Value, parentXElement.Descendants("child").Select(ParseChild));
}

Of course I can init the Parent property within Parent constructor, just remove the private from Parent setter and then go trhough all children and use this property. But I want to make it read-only. Something like this:

public Parent(string id, string name, IEnumerable<Child> children)
{
    Id = id;
    Name = name;
    Children = children.ForEach(c => c.ParentInstance = this);
}
like image 651
Antony Blazer Avatar asked Jan 20 '14 14:01

Antony Blazer


1 Answers

To be immutable and include cyclic references, you'd need something like this:

public sealed class Parent
{
    private readonly IEnumerable<Child> children;
    private readonly string name; // Just for example

    public Parent(XElement element)
    {
         name = (string) element.Attribute("name");
         children = element.Elements("Child")
                           .Select(x => new Child(x, this))
                           .ToImmutableList(); // Or whatever collection you want
    }
}

public sealed class Child
{
    private readonly Parent parent;
    private readonly string name; // Just for example

    public Child(XElement element, Parent parent)
    {
        this.name = (string) element.Attribute("name");
        // Better not ask the parent for its children yet - they won't be
        // initialized!
        this.parent = parent;
    }
}

The comment in the Child constructor is the bit that should make you raise your eyebrows. Even though Parent is immutable, we're leaking this before we've finished initializing it... so the Child constructor needs to make sure it doesn't try to find its siblings during construction.

like image 56
Jon Skeet Avatar answered Oct 31 '22 18:10

Jon Skeet