1

Are class declarations that are initially set, internally the same as setting them in the constructor?

example:

class test
{
     int test1 = 5;
}

Is there any difference between that and

class test
{
     int test1;
     public test()
     {
         test1 = 5;
     }
}  

If there is no difference, which is more correct to do?

Thomas
  • 6,032
  • 6
  • 41
  • 79

5 Answers5

3

In the specific case you give there is no functional difference. However, when inheritance is involved, field initializers can behave in surprising ways. Field initializers are actually called before the constructor, and while constructors are called from least-derived to most-derived, field initializers are called from the most-derived to least-derived. So if class A derives from B. When an instance of A is created, the following sequence is executed: A's field initializers, B's field initializers, System.Object constructor, B's constructor, A's constructor.

The above only applies to instance field initializers/constructors. For static field initializers/constructors, the behavior is completely different.

As to which is correct in your case, there is no agreed upon convention, but consistency is usually appreciated by readers.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
2

For most purposes, you can consider the two styles of member initialization functionally equivalent.

However, you should keep in mind that assignments made in the member declarations execute before any constructors execute. As Jon Skeet points out in comments, this difference in timing can create observable artifacts if virtual methods are called from base constructors.

"Correctness" is a matter of opinion. For simple integer values the initial value assignments seem innocuous enough, but when you get into more complex types like dates or other full-on objects, the clutter factor starts to rise.

For myself, I generally prefer to see initialization performed as explicit assignment statements in the body of the constructor, not scattered all over the class in declarations.

dthorpe
  • 35,318
  • 5
  • 75
  • 119
  • 2
    In general they're *not* functionally equivalent - assignments made in the member declarations execute before the *base* class constructor too. If your base class constructor calls into some virtual method overridden in the derived class, it won't see any initialization from the constructor body, but variable initializers *will* have been executed. – Jon Skeet Jul 31 '12 at 06:04
  • Good point, had forgotten about observability of the timing difference via virtual calls in constructors. Text updated. – dthorpe Jul 31 '12 at 18:03
1

When looking at the IL code differnce, you can see that in case 1 the variable test is assigned before the constructor is called, and in case 2 it is assigned after the constructor is called.

Case 1

.class public auto ansi beforefieldinit WebApplication1.Class1
    extends [mscorlib]System.Object
{
    // Fields
    .field public int32 test1

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x28d3
        // Code size 15 (0xf)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldc.i4.5
        IL_0002: stfld int32 WebApplication1.Class1::test1 <- HERE
        IL_0007: ldarg.0
        IL_0008: call instance void [mscorlib]System.Object::.ctor()  <- HERE
        IL_000d: nop
        IL_000e: ret
    } // end of method Class1::.ctor

} // end of class WebApplication1.Class1

Case 2

.class public auto ansi beforefieldinit WebApplication1.Class2
    extends [mscorlib]System.Object
{
    // Fields
    .field public int32 test1

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x28e3
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor() <- HERE
        IL_0006: nop
        IL_0007: nop
        IL_0008: ldarg.0
        IL_0009: ldc.i4.5
        IL_000a: stfld int32 WebApplication1.Class2::test1 <- HERE
        IL_000f: nop
        IL_0010: ret
    } // end of method Class2::.ctor

} // end of class WebApplication1.Class2
Adriaan Stander
  • 162,879
  • 31
  • 289
  • 284
0

In you case its one and the same thing. But what if there are parameterised constructors and test1 was assigned from values passed from constructors.

class test
{
    int test1;
    public test()
    {
        test1 = 5;
    }

    public test(int ctest)
    {
        test1 = ctest;
    }
}

If there is no difference, which is more correct to do?

Its upto developer to choose which one he wants.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
0

This one is called Instance field initialization:

class Test
{
     int test1 = 5;
}

How does it work?

The instance field variable initializers of a class correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors (Section 10.10.1) of that class. The variable initializers are executed in the textual order in which they appear in the class declaration.

So, in your case these two variants of field initialization are functionally the same.

Also, I would like to recommend you to take a look at this question: C# member variable initialization; best practice?.

Community
  • 1
  • 1