Initialize private fields in declaration or constructor?

8

I'm modeling a class that has a private list and an internal dependency to another object:

public class Teste
{
    private IList<string> Textos;
    private Teste2 Teste2;
}

I can initialize them in the declaration:

private IList<string> Textos = new List<string>();
private Teste2= new Teste2();

Or via constructor:

public Teste()
{
    Textos = new List<string>();
    Teste2 = new Teste2();
}

Which of the two approaches is recommended? Is it just a matter of coding style or does one of them hurt some principle of object orientation?

    
asked by anonymous 14.04.2017 / 02:59

3 answers

10

It really does not have the field being initialized by itself, you need a code to do this. And codes can only be put into methods. If it is a field that is being initialized a method in construction needs to be executed by doing the initialization. So the boot in the field is an illusion, in fact this is thrown at the builder even if you do not see it like that. Then it's the same.

See how the same .

With field initialization:

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 18 (0x12)
    .maxstack 8

    IL_0000: ldarg.0              // Load argument 0 onto the stack
    IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List'1<string>::.ctor() // Allocate an uninitialized object or value type and call ctor
    IL_0006: stfld class [mscorlib]System.Collections.Generic.IList'1<string> Teste::Textos // Replace the value of field of the object obj with value
    IL_000b: ldarg.0              // Load argument 0 onto the stack
    IL_000c: call instance void [mscorlib]System.Object::.ctor() // Call method indicated on the stack with arguments
    IL_0011: ret                  // Return from method, possibly with a value
} // end of method Teste::.ctor

With initialization in the constructor:

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x2063
    // Code size 18 (0x12)
    .maxstack 8

    IL_0000: ldarg.0              // Load argument 0 onto the stack
    IL_0001: call instance void [mscorlib]System.Object::.ctor() // Call method indicated on the stack with arguments
    IL_0006: ldarg.0              // Load argument 0 onto the stack
    IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List'1<string>::.ctor() // Allocate an uninitialized object or value type and call ctor
    IL_000c: stfld class [mscorlib]System.Collections.Generic.IList'1<string> Teste2::Textos // Replace the value of field of the object obj with value
    IL_0011: ret                  // Return from method, possibly with a value
} // end of method Teste2::.ctor

Note that the compiler always creates a constructor even if you do not declare it. And it puts the base class's constructor call into the constructor. It does this as early as possible, inside the constructor . In case of having fields with initializers this is placed inside the constructor before the base builder is called.

It is important to note that the Object constructor will probably disappear since it is empty and JITter should delete it.

You can see more about this in New feature of C # 6 "Auto-property initializers" is it just a facilitator? .

Understand What is a builder for? and why should you use it or not.

I tend to avoid the builder whenever possible. You have to use what makes the most sense for that case.

    
14.04.2017 / 03:37
3

For most cases, either initialize the declaration or the constructor if you want to give it a default value. The object only exists in memory even at the time it is built.

If you want to be very pedantic, you can debug the object construct and you will notice that the properties initialized in the statement are given values before the start of the constructor method that you declared. But that does not have much practical effect.

Regarding best practices: each case is a case, so instead of discussing which form is most advisable, it is more beneficial to know the advantages and disadvantages of each form.

Declaring values in the constructor has the advantage that things tend to be concentrated in a single point, or at least a few points in the case of multiple constructors. Compare:

public class Foo
{
    public Foo()
    {
        this.A = new {};
        this.B = new {};
        this.C = new {};
        this.D = new {};
        // etc., etc.
        this.Z = new {};
    }
}

With:

public partial class Foo // Atenção especial para o partial
{
    // 26 propriedades

    public Foo()
    {
        /* Seus colegas perguntaram qual era o valor padrão da propriedade Y
         * e você veio procurar aqui. E você provavelmente abriu este código
         * no github e não em uma IDE. Vou dar uma dica, a declaração está
         * em outro arquivo. Descobrir qual será o seu desafio. Compartilhe
         * se você encontrar em até 60 segundos.
         */

         // Sério, não tem código aqui. Este é um construtor vazio.
    }
}

Already initializing the statement can have its advantages there if you are working with properties. You can do Lazy Loading ("lazy load"), as follows:

private List<string> _afazeres;
public List<string> Afazeres
{
    get
    {
        if (this._afazeres == null)
        {
            this._afazeres = new List<string>()
            {
                "Programar",
                "Postar no Stack Overflow",
                "Estudar",
                "Beber café até morrer",
                "Fazer tudo de novo"
            }
        }
        return this._afazeres;
    }
    set { this._afazeres = value; }
}

This ensures that your class can be instantiated without allocating memory for some field - that field will only take up space from the first time it is accessed. Here we have a short list of strings, but this could be some really heavy object.

    
14.04.2017 / 04:08
-2

Advantage of Initializing Declaration

As it was said , "Initialize the Declaration" is not really what happens, but I will use this term in this answer. If you initialize in the Declaration it is easier to know what is in the variable when the instance is created, therefore it is only to find the Declaration of the Variable. This is the Most Simple Solution .

With builders you can do more

With a constructor you can dynamically define the variable content in the instance creation, using different constructors that assign different things to the variable and / or Parameters in the constructor that will be used to define the value of the variable.

Therefore, builders give you greater flexibility in defining the contents of the variable when the instance is created, but increase Complexity .

Disadvantages of using Builders

  • If you have multiple constructors, each set a different value for the variable, you need to know which constructor was used to create the instance to know what is in the variable when the instance was created. This makes debugging difficult.

  • If the value of the variable is defined through a Parameter in a constructor, you need to know what was passed by this parameter to know what is in the variable when the instance was created. This also makes debugging difficult.

  • The complexity of the project and the amount of code increases when declaring Builders, this can make your project more difficult to understand (there will be more code to study).

Conclusion

Use Builders only when it's really needed , otherwise you'll be creating Unnecessary Complexity . If you know you will not need the builder (s) you are thinking of creating, do not create them, initialize the declaration.

    
15.04.2017 / 01:21