Rolls, Robert [mailto:[EMAIL PROTECTED]] wrote:
> Do people still use the constructor to define default values > to members or has the default constructor been depreciated? > Are there any reasons not to use to the following? > > public byte[] arr = new byte[1024]; > > rather than > > public byte[] arr = null; > > then within the constructor > arr = new byte[1024]; Robert, first a disclaimer: the following are results of the C# compiler, other compilers may do things differently. That said: When member variables are initialized at declaration time, the initialization code is injected into *each* constructor[1a][1b]. So you technically get a little IL bloat, where as if you deferred to your own default constructor from overloaded constructors you can avoid that[2a][2b]. Then again depending on the JIT implementation, if it doesn't inline the default constructor... you'd pay a runtime perf. hit for the jmp. My guess is the MS JIT, on a release build, would inline such a scenario, but perhaps someone more intimately familiar with the JIT can fill us in. Out of curiousity I just tried another scenario[3a][3b] and it looks like the C# compiler is smart enough to automagically avoid injecting initialization code into any constructor that defers to another constructor. Next, notice the initialization code is also for declaration time initialized variables is executed *prior* to the base class' constructor being called, whereas if you actually initialized the member variables in the constructor the base constructor would be called first. I don't see this making a big difference other than maybe you could be wasting some time and, depending on how the CLR is implemented, some memory (assuming the member variables are reference types) if the base class' constructor threw an exception. The memory would of course be cleaned up eventually at the next GC anyway, but it was allocated none-the-less. Beyond that... I really don't see any differences other than syntatic preference. So going on the assumption that the JIT will inline deferring calls to other constructors, #2 looks to be the best approach. You avoid IL bloat and the base class' constructor is called first which avoids any potential time or memory wasted by declaration time initialized variables. HTH, Drew .NET MVP [1a] <codeSnippet language="C#"> public class MyClass1 { private int someValue = 1; private int someOtherValue; public MyClass1() { } public MyClass1(int someOtherValue) { this.someOtherValue = someOtherValue; } } </codeSnippet> [1b] <codeSnippet language="CIL"> .class public auto ansi beforefieldinit MyClass extends [mscorlib]System.Object { .field private int32 someValue .field private int32 someOtherValue .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: stfld int32 Gnutella.Net.classes.MyClass::someValue IL_0007: ldarg.0 IL_0008: call instance void [mscorlib]System.Object::.ctor() IL_000d: ret } // end of method MyClass::.ctor .method public hidebysig specialname rtspecialname instance void .ctor(int32 someOtherValue) cil managed { // Code size 21 (0x15) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: stfld int32 Gnutella.Net.classes.MyClass::someValue IL_0007: ldarg.0 IL_0008: call instance void [mscorlib]System.Object::.ctor() IL_000d: ldarg.0 IL_000e: ldarg.1 IL_000f: stfld int32 Gnutella.Net.classes.MyClass::someOtherValue IL_0014: ret } // end of method MyClass::.ctor } // end of class MyClass </codeSnippet> [2a] <codeSnippet language="C#"> public class MyClass2 { private int someValue; private int someOtherValue; public MyClass2() { this.someValue = 1; } public MyClass2(int someOtherValue) : this() { this.someOtherValue = someOtherValue; } } </codeSnippet> [2b] <codeSnippet language="CIL"> .class public auto ansi beforefieldinit MyClass2 extends [mscorlib]System.Object { .field private int32 someValue .field private int32 someOtherValue .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldc.i4.1 IL_0008: stfld int32 Gnutella.Net.classes.MyClass2::someValue IL_000d: ret } // end of method MyClass2::.ctor .method public hidebysig specialname rtspecialname instance void .ctor(int32 someOtherValue) cil managed { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: call instance void Gnutella.Net.classes.MyClass2::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld int32 Gnutella.Net.classes.MyClass2::someOtherValue IL_000d: ret } // end of method MyClass2::.ctor } // end of class MyClass2 </codeSnippet> [3a] <codeSnippet language="C#"> public class MyClass3 { private int someValue; private int someOtherValue; public MyClass3() { } public MyClass2(int someOtherValue) : this() { this.someOtherValue = someOtherValue; } } </codeSnippet> [3b] <codeSnippet language="CIL"> .class public auto ansi beforefieldinit MyClass3 extends [mscorlib]System.Object { .field private int32 someValue .field private int32 someOtherValue .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: stfld int32 Gnutella.Net.classes.MyClass3::someValue IL_0007: ldarg.0 IL_0008: call instance void [mscorlib]System.Object::.ctor() IL_000d: ret } // end of method MyClass3::.ctor .method public hidebysig specialname rtspecialname instance void .ctor(int32 someOtherValue) cil managed { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: call instance void Gnutella.Net.classes.MyClass3::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld int32 Gnutella.Net.classes.MyClass3::someOtherValue IL_000d: ret } // end of method MyClass3::.ctor } // end of class MyClass3 </codeSnippet> You can read messages from the DOTNET archive, unsubscribe from DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.