2

I came across a source code with a nested class like this:

public class OuterClass
{
  // code of the outer class

  protected class NestedClass
  {
    private string myVar;

    private NestedClass() {} // <--- empty private ctor

    public NestedClass(string myVar)
    {
      this.myVar = myVar;
    } 
  }
}

What could be the reason to create this empty private constructor?

I know when implementing a singleton the constructor must be private to prevent other classes to create an instance. However in the case the is another public constructor, so this cannot be the reason.

One reason I thought of would be to not allow the creation of an instance without a value for the variable, that is passed as parameter to the public constructor, but as far as I know this shouldn't be possible when the is simple no other constructor than the public constructor with parameter. Is that correct?

Edit: A answer that was deleted now, mentioned the default constructor. As far as I know a "hidden" default constructor only exists if there is no manually written constructor at all. This is described here:

These constructors are injected into all class declarations that do not introduce other constructors.

Therefore the empty constructor of my nested class, is not a default constructor, but simply a constructor without parameters. I assume that this is the case for top-level classes and nested classes alike.

Philipp M
  • 1,877
  • 7
  • 27
  • 38
  • That code doesn't compile. I guess you meant `private NestedClass(){}` – Matthew Watson Jan 14 '15 at 13:34
  • Unless you were creating instances of `NestedClass` within itself, then the private empty constructor doesn't apply to creating instances outside of the class. – Ric Jan 14 '15 at 13:35
  • @MatthewWatson you are right – Philipp M Jan 14 '15 at 13:35
  • I can see no point in making the default constructor private, other than making it possible to call it via reflection. – Matthew Watson Jan 14 '15 at 13:37
  • @PhilippM Based on the code context, NestedClass can't be instantiated using default constructor. The restriction it imposes is: always use parameterized constructor, where the value of parameter is important to build the instance. – Siva Gopal Jan 14 '15 at 13:46
  • @SivaGopal that is exactly what I meant in the second paragraph of my question. Is my assumption correct, that I wouldn't need the empty constructor to impose this restriction? – Philipp M Jan 14 '15 at 13:50
  • @PhilippM IMHO, I can say YES. And in any case if you have option open for reflection on that class then [this](http://stackoverflow.com/questions/178645/how-does-wcf-deserialization-instantiate-objects-without-calling-a-constructor#179486) and [this](http://stackoverflow.com/questions/390578/creating-instance-of-type-without-default-constructor-in-c-sharp-using-reflection) may help you. – Siva Gopal Jan 14 '15 at 13:56
  • @SivaGopal I don't need to call the constructor and I wouldn't want to use reflection, but thank you! – Philipp M Jan 14 '15 at 14:01

3 Answers3

2

If you have a non-default constructor and do not specify a default constructor, it will not be possible for any code to access the default constructor, because the compiler will not create one.

If you have a non-default constructor and also specify a private default constructor then it is possible for a NestedClass method to use the default constructor. Your code does not do this, so it is not necessary to provide a default constructor (private or otherwise).

There also an obscure case where it can make a difference: By providing the default NestedClass constructor, you enable reflection to access it.

The following program demonstrates.

If you run it, it will print "Demo.OuterClass+NestedClass".

If you comment-out the private default NestedClass constructor and run it, it will crash.

Other than this unlikely case, I can see no sensible reason to provide the private constructor.

using System;
using System.Reflection;

namespace Demo
{
    public class OuterClass
    {
        protected class NestedClass
        {
            private string myVar;

            private NestedClass(){} // Commenting-out this line will cause the reflection to break.

            public NestedClass(string myVar)
            {
                this.myVar = myVar;
            }
        }
    }

    public class MyDerivedClass: OuterClass
    {
        public MyDerivedClass()
        {
            Type type = typeof(NestedClass);
            var ctor = type.GetConstructor(BindingFlags.Instance|BindingFlags.NonPublic, null, Type.EmptyTypes, null);
            var nested = (NestedClass) ctor.Invoke(null);

            Console.WriteLine(nested);
        }
    }

    public static class Program
    {
        private static void Main()
        {
            var test = new MyDerivedClass();
        }
    }
}

If you don't want to explicitly allow reflection to call the private default constructor, then I would say that there is indeed no point in providing it, and you should remove it from the code.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • My guess is that you are right and I should remove it from the code, but I will wait if someone else answers with a reason, before I accept your answer. Thank you! – Philipp M Jan 14 '15 at 14:09
0

I think this means that only this class can create instances of itself using this constructor. Does the code in the class call this constructor anywhere?

  • The empty constructor is not called from anywhere. – Philipp M Jan 14 '15 at 13:39
  • I found this that seems to back up what I was saying http://stackoverflow.com/questions/16151799/what-is-the-purpose-of-private-parameterless-constructor-in-c-sharp –  Jan 14 '15 at 16:11
  • You are right, but it doesn't answer my question. Thanks anyway! – Philipp M Jan 14 '15 at 16:17
0

Normally you'd have a private constructor if the class wanted to restrict you to calling some sort of factory method defined on it in order to create it, but as there's another constructor defined then this doesn't seem to be the case.

You can use reflection to locate the private constructor, and once you've got the ConstructorInfo for the private constructor you can invoke it in order to create an instance of the class, but this would be a very niche thing to do!

Sean
  • 60,939
  • 11
  • 97
  • 136