Fork me on GitHub

.net知识和学习方法系列(十八)CLR-构造函数

构造函数也叫构造方法,是一个比较特殊的函数,因为它没有返加回值,并且名称与所在类的类名相同。

构造函数有两种,一种是实例构造函数,一种是静态构造函数。

现有一个类:

    class Test

    {    

}

这个类与下面的类完全等价

    class Test

    {

        static Test()

        {

        }

        public Test()

        {

        }   

 }

也就是说,如果定义完一个类后,IDE会自动在类的内部定义一个实例化函数的。

如果在类中有字段的初始化,表态构造函数也会默认在类中,因为静态字段的初始化是在静态构造函数中实现的.

这两个构造函数是有区别,如果类中有静态构造函数,静态构造函数只在该类的第一个对象被实例化或有静态成员被调用时才调用,而实例化构造函数,则是在每次对象被实例化时调用。

实例构造函数可以有多个,通过参数来区分,或者参数的个数不同,或者参数的类型不能,也就是所谓的重载。但静态构造函数则有且只能有一个,并且不能有任何参数。

 

下面再看一下这个例子

class Test

{

        int a=1, b=2, c=3;

        int d;

        public Test()

        {

        }

        public Test(int i)

        {

        }

        public Test(string s)

        {

        }  

}

表面上看来没有什么,就是一个类中有三个构造函数,还有三个字段。

现在让我们看看IL吧

首先看一下这个类的IL

其中三个.ctor就是三个实例构造函数,双击三个构造函数来看一下它的IL代码:

Test()→.ctor:void()

.method public hidebysig specialname rtspecialname

        instance void .ctor() cil managed

{

 // 代码大小       31 (0x1f)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: ldc.i4.1

 IL_0002: stfld      int32 ConsoleApplication1.Test::a

 IL_0007: ldarg.0

 IL_0008: ldc.i4.2

 IL_0009: stfld      int32 ConsoleApplication1.Test::b

 IL_000e: ldarg.0

 IL_000f: ldc.i4.3

 IL_0010: stfld     int32 ConsoleApplication1.Test::c

 IL_0015: ldarg.0

 IL_0016: call       instance void [mscorlib]System.Object::.ctor()

 IL_001b: nop

 IL_001c: nop

 IL_001d: nop

 IL_001e: ret

} // end of method Test::.ctor

Test(int i)→.ctor:void(int32)

.method public hidebysig specialname rtspecialname

        instance void .ctor(int32 i) cil managed

{

 // 代码大小       31 (0x1f)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: ldc.i4.1

 IL_0002: stfld      int32 ConsoleApplication1.Test::a

 IL_0007: ldarg.0

 IL_0008: ldc.i4.2

 IL_0009: stfld      int32 ConsoleApplication1.Test::b

 IL_000e: ldarg.0

 IL_000f: ldc.i4.3

 IL_0010: stfld      int32 ConsoleApplication1.Test::c

 IL_0015: ldarg.0

 IL_0016: call       instance void [mscorlib]System.Object::.ctor()

 IL_001b: nop

 IL_001c: nop

 IL_001d: nop

 IL_001e: ret

} // end of method Test::.ctor

Test(string s)→.ctor:void(string)

.method public hidebysig specialname rtspecialname

        instance void .ctor(string s) cil managed

{

 // 代码大小       31 (0x1f)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: ldc.i4.1

 IL_0002: stfld      int32 ConsoleApplication1.Test::a

 IL_0007: ldarg.0

 IL_0008: ldc.i4.2

 IL_0009: stfld      int32 ConsoleApplication1.Test::b

 IL_000e: ldarg.0

 IL_000f: ldc.i4.3

 IL_0010: stfld      int32 ConsoleApplication1.Test::c

 IL_0015: ldarg.0

 IL_0016: call       instance void [mscorlib]System.Object::.ctor()

 IL_001b: nop

 IL_001c: nop

 IL_001d: nop

 IL_001e: ret

} // end of method Test::.ctor

 

很明显的看到三个实例构造函数都对a,b,c进行了初始化赋值即造成了代码的重复。

如果初始化的字段更多,构造函数更多,重复量就更大。

但值的注意的是,在Test类中有一个字段d,没有初始化,并且在所有的构造函数中也没有发现它,这个,就给我们避免代码重复提供了一个方法。

改造一下上面的代码:

class Test

    {

        int a,b,c;

        int d;

        public Test()

        {

            a = 1;

            b = 2;

            c = 3;

        }

        public Test(int i):this()

        {

        }

        public Test(string s):this()

        {

        }

    }

就在类中,先不去初始化字段,只在没有参数的实例构造函数中初始化,用其他构造函数来调用它,现在来看一下IL

 

Test()→.ctor:void()

.method public hidebysig specialname rtspecialname

        instance void .ctor() cil managed

{

 // 代码大小       31 (0x1f)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: call       instance void [mscorlib]System.Object::.ctor()

 IL_0006: nop

 IL_0007: nop

 IL_0008: ldarg.0

 IL_0009: ldc.i4.1

 IL_000a: stfld      int32 ConsoleApplication1.Test::a

 IL_000f: ldarg.0

 IL_0010: ldc.i4.2

 IL_0011: stfld      int32 ConsoleApplication1.Test::b

 IL_0016: ldarg.0

 IL_0017: ldc.i4.3

 IL_0018: stfld      int32 ConsoleApplication1.Test::c

 IL_001d: nop

 IL_001e: ret

} // end of method Test::.ctor

Test(int i)→.ctor:void(int32)

.method public hidebysig specialname rtspecialname

        instance void .ctor(int32 i) cil managed

{

 // 代码大小       10 (0xa)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: call       instance void ConsoleApplication1.Test::.ctor()

 IL_0006: nop

 IL_0007: nop

 IL_0008: nop

 IL_0009: ret

} // end of method Test::.ctor

Test(string s)→.ctor:void(string)

.method public hidebysig specialname rtspecialname

        instance void .ctor(string s) cil managed

{

 // 代码大小       10 (0xa)

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: call       instance void ConsoleApplication1.Test::.ctor()

 IL_0006: nop

 IL_0007: nop

 IL_0008: nop

 IL_0009: ret

} // end of method Test::.ctor

会发现,在有参数的两个构造函数中的IL要少很多,这样就能减少IL代码量。

 

在类中,如果有初始化的静态字段,会在静态构造函数中来实现,不过静态构造函数只能有一个,所以这个在代码量中问题不会存在。

 

可以看出,在类中,如果有初始化的字段,他的执行要先于对象的生成,即构造函数的执行(完全执行)。
posted @ 2008-09-18 20:40  桂素伟  阅读(881)  评论(3编辑  收藏  举报