Make the class builder private?

Asked

Viewed 1,682 times

20

When placing a constructor of a class in C# as private, get the following error:

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

I would like to know the technical explanation for the reason of this error and whether there is any case of use of a builder (or one of the builders) of a class as private.

7 answers

15

A private constructor is useful in cases where you want to prevent the class from being instantiated or want to allow it to be instantiated only within itself. This is useful for static classes or to implement design standards Singleton and Factory.

An example can be found in that reply. Other examples are obviously in the other answers here.

Singleton (taken from Wikipedia):

public class Program {
    public static void Main() {
        var singleton = MyClass.Instance;
    }
}

public class MyClass {
   private static MyClass instance;
   private MyClass() {}
   public static MyClass Instance {
      get {
         if (instance == null) instance = new MyClass();
         return instance;
      }
   }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

  • 2

    Only not useful for static classes declared as such because a class declared as static cannot be instantiated and can even have constructors, even if private.

  • @Caffé yes, of course.

  • @Caffé All classes have constructors, the constructors of static classes are more restrictive, but they exist. Read my answer to see an example.

  • @Malkavian Yes, I’ve even used this type of builder. But it has nothing to do with declaring a constructor as private in order to make it inaccessible - a static constructor even accepts access modifiers.

9

The technical explanation is simple: the constructor cannot be accessed from outside the class. Hence the error.

Private constructors are important when you want to force parameters for the exposed constructors (public). For example, constructors without parameters could be declared private so that their use is avoided. There is a caveat here: the builder without parameters needs to do something, otherwise his statement makes no sense.

For example:

public class MinhaClasse 
{
    protected int MeuInteiroQuePrecisaSerPreenchido { get; set; }
    protected int OutraProperty { get; set; }

    // inacessível, portanto não pode ser usado fora da classe.
    private MinhaClasse() 
    { 
        OutraProperty = 5;
    } 

    // Aqui eu chamo o construtor sem parâmetros. 
    public MinhaClasse(int _meuInteiro) : this()
    {
        MeuInteiroQuePrecisaSerPreenchido = _meuInteiro;
    }
}

By default, the constructor without class parameters is public.

Still, suppose you want to define several constructs (for checking data of arguments, for example). You can make builders with varying levels of protection:

public class MinhaClasse2
{
    protected int MeuInteiro { get; set; }
    protected int OutraProperty { get; set; }
    protected String MinhaStringComValidacao { get; set; }

    // inacessível, portanto não pode ser usado fora da classe.
    private MinhaClasse() 
    { 
        OutraProperty = 5;
    } 

    private MinhaClasse(String _minhaString) : this()
    {
        if (_minhaString != "Valor que não pode") 
        {
            MinhaStringComValidacao = _minhaString;
        }
    }

    public MinhaClasse(int _meuInteiro, String _minhaString) : this(_minhaString)
    {
        MeuInteiro = _meuInteiro;
    }
}

Silly example, but only to demonstrate how it can be done.

  • 1

    If the constructor cannot be used, what is the real utility of even declaring it?

  • @Luishenrique Force the programmer to use a constructor with parameters, or as in André Ribeiro’s answer, prevent static classes from being instantiated.

  • 4

    The first reason shown is invalid. A class that only has parameterized constructors cannot be instantiated using a non-paracterized constructor - the compiler does not allow; it is not necessary to explicitly declare an non-paracterized constructor as private.

  • 1

    The @Caffé is right

  • It’s not. I can perfectly implement a generic class with the statement where T: class, new(). In a class without the declaration private, the code passes and the object is instantiated smoothly. The first argument prevents this from being used.

  • The @Caffé is right, yes. Note: https://dotnetfiddle.net/YyElx9.

  • 1

    The 2nd reason is also 'invalid. Static classes (declared as static class SomeClass{}), by definition, cannot be instantiated. So saying that private constructors serve to "prevent static classes from being instantiated" doesn’t even make sense. It may make sense in java, where classes cannot be declared as statics, but not in c#.

  • 1

    @Romaniomorrisonmendez, a class that has only parameterized constructors, cannot be passed to a Generic that requires a non-paracterized constructor - this is already prevented by the compiler without the need to declare a private constructor. See: https://dotnetfiddle.net/5xTFHJ

  • 1

    @Caffe, I agree with the Gypsy, I can have a class with private contrutor and static properties of the same kind of class to which they belong, so only objects initiated through the static properties can be accessed.

  • 2

    @Tobymosque I understand that this is a good reason to have private builders. But no one is questioning its usefulness, we are questioning the usefulness as proposed by Gypsy, which has nothing to do with it.

  • 2

    I edited the answer.

  • 1

    After editing: the first example does not make sense, the constructor will never be called - there is no need to be declared. The 2nd example also has no utility, there is no reason for "null check" not to be made inside the public constructor.

  • I am not discussing the merit of utility. I am only pointing out what can be done.

  • But the question is precisely about the usefulness of this Feature, not how to use it: "if there is any use/utility case in using a constructor (or one of the constructors) of a class as private"

  • So please read my edition and do not reduce yourself to criticism. Just criticize nothing adds to this site or to the doubt made.

  • I read the issue, and made a constructive criticism because I do not consider the answer useful, and does not clarify the doubt placed. I disagree with this last phrase: to criticize helps a lot. Anyway, I have already written my own answer - I accept criticism.

Show 11 more comments

9


We have a lot of good answers here but since I grumbled at something in each of them, I think it’s only fair that I expose my own.

As already said, the reason for the error is that you are trying to use a class member (the constructor) that is not accessible outside of it due to the fact that it is private.

And yes, there are cases of use or utility in declaring a constructor as private:

Declare a private constructor when you want this constructor to be accessible only to the class itself and its nested classes.

Sometimes only the class itself knows its constraints to be instantiated, so it is at these times that you declare the constructor as private. These restrictions may be:

  • The class wants to restrict only a single instance of itself throughout the application lifecycle (design Pattern Singleton).

  • The class wants to control its instances - for example by pooling instances of itself, so it itself creates its instances (design Pattern Factory) and decides when to deliver a new instance or when to deliver an existing instance.

  • The class requires external consumers to pass certain parameters to the constructor but wants to be able to create instances of itself without passing any parameters or passing parameters that are not of public interest. In this case it would have public parameterized constructors and a private constructor not parameterized or that accepts specific parameters that only need to be known internally.

These are the uses that occur to me at the moment but there may be more.

Besides public and private, a builder can also be protected, which makes it possible for it to be used exclusively by the Child Class Controller, and ternal, which makes it accessible only to classes of the same Assembly.

Internal is useful for example to use the design Pattern Factory or pool of instances causing another class of the same context to be responsible for these restrictions instead of placing all this knowledge within the very class whose instantiation one wants to control.

As for creating a private constructor for static classes, it is not very useful because in this case it is enough to declare the class itself as static (Static class).

6

According to MSDN documentation:

A private constructor is a special instance constructor. It is generally used in classes that contain only static members. If a class has one or more private builders and no public constructor, other classes (except nested classes) may not create instances of that class.

For example:

class NLog
{
    // Construtor privado:
    private NLog() { }

    public static double e = Math.E;  //2.71828...
}

Empty constructor declaration prevents automatic generation of a default constructor. Note that if you do not specify a modifier of access the constructor will still be private by default. However, the modifier private is usually used explicitly to make clear that the class cannot be instantiated.

Builders are used to avoid creating instances of a class when there are no instance fields or methods, as in the Math class, or when a method is called to obtain an instance of a class. If all class methods are static, consider making the entire class static.

Example:

public class Counter
{
    private Counter() { }
    public static int currentCount;
    public static int IncrementCount()
    {
        return ++currentCount;
    }
}

class TestCounter
{
    static void Main()
    {
        // A instrução abaixo irá gerar um erro porque o construtor é inacessível
        // Counter aCounter = new Counter();   // Erro

        Counter.currentCount = 100;
        Counter.IncrementCount();
        Console.WriteLine("New count: {0}", Counter.currentCount);

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: New count: 101
  • 1

    A class that only has static members can be declared static itself, so as to dispense with the private constructor’s declaration because a static class cannot be instantiated. Nonsense this sentence of this Microsoft documentation.

  • @Caffé I improved the translation of the last paragraph that was not good. Take a look at the last sentence.

4

This is a concrete case, implemented by the ASP.NET Web Api team on Github: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/Results/OkResult.cs

I myself have applied the same pattern here.

Briefly, the above two links show a pattern variation "Parameter Object". Public constructors of the class receive either their dependencies directly, or another object containing their dependencies.

Both public constructors involve the arguments in an instance of IDependencyProvider, which is passed to a private constructor who extracts dependencies and treats them evenly. This constructor is considered a detail of implementation, customers do not need to know about it, and therefore it is 'private.

public class MyClass
{
    private readonly string _dependency1;
    private readonly string _dependency2;

    public MyClass(string dependency1, int dependency2)
        : this(new DirectDependencyProvider(dependency1, dependency2))
    {
    }

    public MyClass(Container container)
        : this(new ContainerDependencyProvider(container))
    {
    }

    //constructor privado
    private MyClass(IDependencyProvider provider)
    {
        _dependency1 = provider.Dependency1;
        _dependency2 = provider.Dependency2;

        //etc, fazer alguma coisa com as duas dependencias
    }

    private interface IDependencyProvider
    {
        string Dependency1 { get; }
        int Dependency2 { get; }
    }

    private class DirectDependencyProvider : IDependencyProvider
    {
        private readonly string _dependency1;
        private readonly int _dependency2;

        public DirectDependencyProvider(string dependency1, int dependency2)
        {
            _dependency1 = dependency1;
            _dependency2 = dependency2;
        }

        public string Dependency1
        {
            get { return _dependency1; }
        }

        public int Dependency2
        {
            get { return _dependency2; }
        }
    }

    private class ContainerDependencyProvider : IDependencyProvider
    {
        private readonly Container _container;

        public ContainerDependencyProvider(Container container)
        {
            if(container == null)
                throw new ArgumentNullException("container");
            _container = container;
        }

        public string Dependency1
        {
            get { return _container.StringStuff; }
        }

        public int Dependency2
        {
            get { return _container.IntStuff; }
        }
    }
}

Note that the interface IDependencyProvider and its implementations are private types.

The alternative would be to use a private boot method, but we would have to sacrifice Fields readonly and the guarantee of its immutability. This is a sacrifice that can and must be avoided.

public class MyClass
{
    private string _dependency1;
    private string _dependency2;

    public MyClass(string dependency1, int dependency2)
    {
        Initialize(dependency1, dependency2);
    }

    public MyClass(Container container)
    {
        if(container == null)
            throw new ArgumentNullException("container");

        Initialize(container.StringStuff, container.IntStuff);
    }

    private void Initialize(string dependency1, int dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
    }
}
  • 2

    Nice to bring a practical example. I even improved the third use case of my answer, inspired by this one.

3

Another use case for a private constructor would be to implement the Singleton Pattern design. By this standard, a class must have only one instance. To ensure this, the Singleton constructor is private. More information: http://en.wikipedia.org/wiki/Singleton_pattern. Just a reminder that Singleton is useful in just a few situations. It has a number of disadvantages( for example, it makes testing difficult ), so it should be used carefully.

  • 1

    Singleton only makes the tests harder if his powers aren’t explicit. If I wish to have just one instance of a class throughout the application lifecycle, it is natural for me to use a Singleton. If I wish to have a good design, I will pass this Singleton by parameter to anyone who needs it, so Singleton itself does not cause any problem. Global mutable objects and hidden dependencies cause trouble.

  • I agree with the point of hidden dependencies. Hidden dependencies suck, especially because they end code flexibility, make it difficult to test, and make the code that uses those dependencies extremely prone to violating the Open-Closed principle. But I still think singletons are hard to test. You mentioned the side of using a Singleton as dependency, but what about the Singleton test itself? Like "mock" a Singleton?

  • You mock the dependency (create a dependency mock) to test the dependent code, it makes no sense to mock what you are going to test. If you are going to test Singleton itself, you will not mock it; and if you are going to test something that depends on Singleton, since the dependency you have on it is explicit you can mock it normally used polymorphism (by inheritance or by interface implementation).

  • What if Singleton makes any HTTP request? In that case, wouldn’t it make sense to mock the class? Unit tests shouldn’t depend on the network...

  • So you want to have a single instance (Singleton) of a class that relies on HTTP communication, and you want to be able to test this class unitarily by mocking this dependency? Do so: https://dotnetfiddle.net/pg8qb5

  • What if the Comunicacaohttp class was a Singleton and you wanted to test it? What I’m talking about is a Singleton who makes an HTTP request himself and not a Singleton who uses a dependency for it...

  • You can draw your solution however you want. I prefer to draw in a way where everything is testable and I can still use a single instance of a class throughout the application lifecycle if I need to.

  • What you posted is different from the problem I pointed out. You tested a Singleton that depends on a class that makes an HTTP request and not a Singleton that makes the HTTP communication itself. In other words, we are talking about different situations. What I wanted to point out is, if you can’t mock a Singleton, then that’s one of his drawbacks, is what makes it harder to test...

  • No, classes of which you want just one instance are not difficult to test - mine, although few, I test very easily. Generally bad designs are hard to test. You’re creating an unnecessary constraint on your Singleton to say that singletons are hard to test - of course it’s easier to make a bad design than a good design, but if you can make a good design without unnecessary restrictions, you can have unique instances of classes with dependencies and yet testable, as in my example.

  • Yes...singletons are hard to test. You ran away from the situation I proposed. What I wanted to show is that Singletons cannot be mocked, and that makes testing difficult. And this is a limitation, so much so that you are running away from the situation that I proposed...as an excuse, it seems that you want to imply that my design is bad without seeing even a line of code that I wrote.

  • A design that cannot be tested in such a modern language is a bad design. If you have unique instances of classes with dependencies (a natural need) that you can’t test, your design is bad. I didn’t run away from anything, I just gave you options to do what you proposed as a challenge (testing classes with dependencies that you need a single instance of). If you prefer a non-tradable solution, go for it.

  • I don’t think you understand. It seems like you think I have a Singleton that does an HTTP request on my project. Isn’t it clear what I said was just to show the Singletons problem? When I said I have a Singleton that makes an HTTP request in some project? It was just an example exactly to show a singleton deficiency. You can’t mock singletons, and that’s a problem. How can something that cannot be mocked not hinder testing? Singletons put a barrier in testing.

  • There are a thousand ways to mock a Singleton. I gave you a good option on how to mock objects of which you want a single instance, and this article from Uncle Bob published yesterday offers some more good options and good ideas that can help you overcome this myth that "Singleton is unstoppable and is evil": http://blog.cleancoder.com/uncle-bob/2015/07/01/TheLittleSingleton.html. Good reading!

Show 8 more comments

0

I believe that most uses are when we want to maintain a DDD and the framework forces us to have default constructor, for example it is the Entity Framework that forces all persisting entities to have constructs without parameter, but does not care about visibility. As you follow the DDD and do not want "anemic" templates do not want class users to be able to use these constructs and use this feature to hide them.

I agree that they also serve to protect classes with purely static methods, but there has the feature of declaring static class, design issue.

@Caffé: All classes have constructors, including static ones. Of course, these constructors have greater restrictions.

Note (linqpad):

void Main()
{
    Console.WriteLine(Xpto.msg);
}

static class Xpto
{
    public static string msg;

    static Xpto()
    {
        msg = "Blau";
    }
}
  • Yes, and this is quite useful for example to define the boot order of class Fields. But it has no relation to declaration of private builders.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.