Search code examples
c#constructoranti-patterns

Hand off instance before constructor returns


I have the habit of breaking the rules if it makes my code more concise or my API more convenient to use, and if I can thoughtfully get away with doing so in the specific circumstances. I'd like to know if I can get away with the following such infringement.

The following illustration includes a single Child and single Parent class. In fact, I am describing a common situation throughout my app. My decision regarding this problem will affect numerous classes, which is why I'm asking this question.

public sealed class Child : INotifyPropertyChanged
{
    private Child()
    {
        //initialize basic state
    }

    public Child( Parent parent )
        : this() //invoke parameterless contructor to initialize basic state
    {
        this.Parent = parent; //the last thing before the public ctor exits
    }

    public Parent Parent
    {
        get { return parent; }
        set
        {
            if ( value != parent ) {
                parent = value;
                // initialize state that depends on the presence of a Parent instance
                parent.Children.Add( this ); //hand off to parent class
                OnPropertyChanged( "Parent" );
            }
        }
    }

    // INotifyPropertyChanged impl...
}

Notice in the Parent property's setter that I hand off the instance to the Parent class. Also notice that I am invoking that setter from the public constructor.

On an earlier question I asked, it came up that handing off an instance that's not fully initialized is an anti-pattern. It may be argued that that's what's happening here. But I would say that it's not the case since basic state is initialized in the parameterless constructor which is called before the one accepting the Parent parameter.

I thought of a problem scenario arising if a Child subclass's constructor calls the base constructor with the Parent parameter. If the derived constructor initializes basic state of its own then it won't be ready in time for the hand off. But I figure I can solve that problem with the sealed keyword, if it fits the class's semantics as it does in my Child class's cases.

So am I good to go with breaking the referenced anti-pattern in these specific circumstances? Or is there some consideration that I missed?


Solution

  • So am I good to go with breaking the referenced anti-pattern in these specific circumstances?

    I think you're good.

    I would do (have done) it myself: especially if a Child must always have a Parent, so that assigning it to the Parent is logically part of constructing the Child.

    Or is there some consideration that I missed?

    One difference is that if the set property throws an exception, then the object is not constructed. That makes a difference if the child is disposable.

    using (Child child = new Child())
    {
       Child.Parent = null; // throws an exception
       ... etc ...
    } // child.Dispose is invoked
    

    versus

    using (Child child = new Child(null)) // throws an exception
    {
       ... etc ...
    } // child.Dispose is not invoked