0

I have some nested classes, BaseOuter and BaseInner, and child classes DerivedOuter and DerivedInner. BaseOuter has property BaseInner baseInner;, and when I instantiate DerivedOuter I want the runtime type of baseInner property to be DerivedInner.

I first solved this like I have below, using a virtual initializer to instantiate baseInner, that is overriden in DerivedOuter. That allows me to do baseInner = new BaseInner(); vs baseInner = new DerivedInner(); in the respective initializers.

After noticing a Resharper warning and doing a little more reading I decided I should change it... but how?

A couple of things come to mind. I could call the initializer after calling the constructor, requiring calling code to do var baseOuter = new BaseOuter(); baseOuter.Initialize();. I can probably use a factory, but I'd have to think about that a little. Lastly, perhaps there is a design flaw in the class-nesting I want to do?

It's worth pointing out that doing new BaseInner(); is expensive, and I don't simply want to create it and throw it away.

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("new BaseOuter");
        var baseOuter = new BaseOuter();
        Console.WriteLine("\nnew DerivedOuter");
        var derivedOuter = new DerivedOuter();
    }

    class BaseOuter{
        protected BaseInner baseInner;
        public BaseOuter(){
            Console.WriteLine("BaseOuter Constructor");
            /*  lots of stuff I want in derived class */

            // This is an anti-pattern I want to avoid
            //https://www.jetbrains.com/help/resharper/2018.2/VirtualMemberCallInConstructor.html
            InitializeInner();
        }

        protected virtual void InitializeInner(){
            Console.WriteLine("    BaseOuter Initialize BaseInner");
            baseInner = new BaseInner();
        }

        protected class BaseInner{
            public int x;
            public BaseInner(){
                /* stuff that is needed in DerivedInner too */
                Console.WriteLine("        BaseInner Constructor");
                x = 2;
            }
        }       
    }

    class DerivedOuter : BaseOuter {
        public DerivedOuter() {
            Console.WriteLine("DerivedOuter Constructor (finished)");
        }

        protected override void InitializeInner(){
            Console.WriteLine("    DerivedOuter Initialize DerivedInner");
            baseInner = new DerivedInner();
        }

        protected class DerivedInner : BaseInner {
            public double y;
            public DerivedInner(){
            Console.WriteLine("        DerivedInner Constructor");
                y = 2d;
            }
        }
    }
}

Output

new BaseOuter
BaseOuter Constructor
    BaseOuter Initialize BaseInner
        BaseInner Constructor

new DerivedOuter
BaseOuter Constructor
    DerivedOuter Initialize DerivedInner
        BaseInner Constructor
        DerivedInner Constructor
DerivedOuter Constructor (finished)

All of the code can be found here in this .NET Fiddle.

Alejandro
  • 623
  • 6
  • 16

1 Answers1

1

Here's an approach.

It's doing the same thing. The difference is in how the derived class "overrides" the implementation of BaseInner. It does so by supplying an implementation to the constructor.

internal class BaseOuter
{
    protected BaseInner baseInner;

    protected internal BaseOuter(BaseInner inner = null)
    {
        baseInner = inner ?? new BaseInner();
        Console.WriteLine("BaseOuter Constructor");
        /*  lots of stuff I want in derived class */

        // This is an anti-pattern I want to avoid
        //https://www.jetbrains.com/help/resharper/2018.2/VirtualMemberCallInConstructor.html

    }

    protected internal class BaseInner
    {
        public int x;

        public BaseInner()
        {
            /* stuff that is needed in DerivedInner too */
            Console.WriteLine("        BaseInner Constructor");
            x = 2;
        }
    }
}

internal class DerivedOuter : BaseOuter
{
    protected internal DerivedOuter()
     :base(new DerivedInner())
    {
        Console.WriteLine("DerivedOuter Constructor (finished)");
    }

    protected internal class DerivedInner : BaseInner
    {
        public double y;

        public DerivedInner()
        {
            Console.WriteLine("        DerivedInner Constructor");
            y = 2d;
        }
    }
}

If you want to do all-out dependency injection you could remove the default from

protected internal BaseOuter(BaseInner inner = null)

Which means that BaseOuter would be completely decoupled from any implementation of BaseInner.

A few other suggestions:

  • I wouldn't nest classes inside each other unless there's a really strong need. It's not used a lot so at first glance it's likely to confuse someone.
  • If baseInner is supposed to be set only when the constructor is called, mark it readonly. (ReSharper will probably suggest that.)
Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • Thanks! `BaseOuter` constructor would have the line `baseInner = inner;` too, correct? – Alejandro Dec 04 '18 at 18:13
  • Yes, I missed a line. The base class would use the implementation provided by the derived class if there is one. But if there isn't one (it's null) then it will specify its own. – Scott Hannen Dec 04 '18 at 18:19
  • Worth mentioning that if we need to create many inner instances we can pass in a delegate function to do that, such as `(arg) => new DerivedInner(arg)`. – Alejandro Dec 04 '18 at 18:48