上海百维科技,上海网站建设 上海软件开发公司热线电话:021-57700304  
  首 页 产品与服务 软件定制 成功案例 思源优势 技术学院 关于我们 联系我们
 
 
思源软件学院 >>> 根目录>>.NET技术>>C# >>>.ctor,.cctor 以及 对象的机关过程
时间是人类发展的空间。——马克思(上海网站建设)

.ctor,.cctor 以及 对象的机关过程


Admin
2012年1月19日

.ctor,.cctor 以及 对象的机关过程


 




.ctor:


简述:机关函数,在类被实例化时,它会被主动调用。


当C#的类被编译后,在IL代码中会呈现一个名为.ctor的办法,它就是我们的机关函数,对应C#中的机关函数。且看下面的代码:


public class Class1

{

    
private string name;

    
private int age;

}




类Class1中没有显示的机关函数,只有两字段,如今用ILDasm.exe打开编译后生成的exe文件,会看到:



可以看到这里有个.ctor,我们没有定义机关函数,但这里却呈现了.ctor,这就说了然:

当没有显示定义机关函数时,会主动生成一个机关函数,它没有参数,没有返回值。

那我们来看看这个.ctor都干了什么吧,双击.ctor打开,在弹出的窗口中可以找到下面的几行代码:

 IL_0000: ldarg.0


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


 IL_0006: ret



上方就是这个.ctor的办法体,看上方的红色行,从字面上可以看出,它是调用(call)了一个类型为System.Object的实例的.ctor()办法,从这就可以证实:


当一个类没有显示声明持续于其它某个类时,它将默认持续自System.Object,并且,在类的机关函数中将会调用其基类的机关办法(.ctor)。

如今对上方的法度小改一下,在声明name时对其初始化:


public class Class1

{

   
private string name = "Lin";

   
private int age;

}



再用ILDasm打开生成的exe文件,打开.ctor,里面有这么几行:

  IL_0000: ldarg.0


 IL_0001: ldstr      "Lin"


 IL_0006: stfld      string ConsoleApplication1.Class1::name


 IL_000b: ldarg.0


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


 IL_0011: nop



这个跟刚才的比拟,多出了红色的那两行,这两行呈如今“调用System.Object的机关办法”之前,这申明:



若是在字段声明的同时对其初始化,那么在编译后,赋值过程将被放到机关办法.ctor中,并且在调用其基类的机关办法之进步行。

如今给上方的C#法度显式加上一个机关办法,它接管两个参数:




public class Class1

{

        
private string name = "Lin";

        
private int age;



        
public Class1(string name, int age)

        
{

            
this.name = name;

            
this.age = age;

        }


}



再用ILDasm打开exe时,会发明有了点变更:

这里的.ctor带了两参数,一个string类型,一个int32类型,而刚才的无参无返回值的.ctor不见了,这也证了然:

若是类中有显式定义机关办法,那么就不会再主动生成一个无参数无返回值的默认机关办法。

打开.ctor,会看到此中有这么几行:


 IL_0000:  ldarg.0


 IL_0001: ldstr      "Lin"


 IL_0006: stfld      string ConsoleApplication1.Class1::name


 IL_000b: ldarg.0


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


 IL_0011: nop


 IL_0012: nop


 IL_0013: ldarg.0


 IL_0014: ldarg.1


 IL_0015: stfld      string ConsoleApplication1.Class1::name


 IL_001a: ldarg.0


 IL_001b: ldarg.2


 IL_001c: stfld      int32 ConsoleApplication1.Class1::age


 IL_0021: nop



从上方红色标识的代码的次序中,我们可以进一步获得:



若是在声明字段时同时对其赋值,那么这个赋值过程将在类型的机关办法(.ctor)中最先履行,然后再履行其基类的机关办法,最后才轮到我们显示定义的机关办法体中代码。


.cctor


简述:类型初始化器,是一个静态办法,无参数无返回值,不克不及直接调用,最多只有一个


我们如今先给刚才的代码加上一个静态字段:

public class Class1

{

        
private string name = "Lin";

        
public static int count = 50;

        
private int age;



        
public Class1(string name, int age)

        
{

            
this.name = name;

            
this.age = age;

        }


}




再来打开ILDasm来看看:

发明这里多了一个.cctor,它就是类型初始化器,打开它,会看到此中有一句:

  IL_0000: ldc.i4.s   50

 IL_0002: stsfld     int32 ConsoleApplication1.Class1::count



它对静态字段count进行了赋值,值是50,那么,是.cctor先调用还是.ctor先调用呢?当然是.cctor,它是为初始化类型而生的,专搞静态的东东,而.ctor是机关办法,当然.cctor要先调用了。



如今显示加上一个.cctor,在C#中就是加个静态机关函数,我们不克不及为其指定接见润饰符(不然编译就会报错):




public class Class1

{

        
private string name = "Lin";

        
public static int count = 50;

        
private int age;



        
static Class1()

        
{

            count 
= 100;

        }




        
public Class1(string name, int age)

        
{

            
this.name = name;

            
this.age = age;

        }


}



再来看看如今ILDasm下的.cctor,此中有几行: 


 IL_0000: ldc.i4.s   50


 IL_0002: stsfld     int32 ConsoleApplication1.Class1::count


 IL_0007: nop


 IL_0008: ldc.i4.s   100


 IL_000a: stsfld     int32 ConsoleApplication1.Class1::count


可以看到:
若是在声明静态字段时同时对其赋值,它在编译后会被搬到.cctor中,并且是放在前面,然后才到显式定义的静态机关办法体中的代码,也就是说count在这里会被赋值两次,第一次50,第二次100。


在持续中对象机关过程


看下面这段法度:


    public class A

    
{

        
public int x = 1;

        
public A() { m1(); }

        
public void m1() { }

    }




    
public class B : A

    
{

        
public int y = 2;

        
public static string sb = "B";

        
public B() { m2(); }

        
public void m2() { }

    }




    
public class C : B

    
{

        
public int z = 3;

        
public static string sc = "C";

        
public C() { m3(); }

        
public void m3() { }

    }




编译后用ILDasm打开生成的exe文件:


可以看到三者都有一个.ctor,B、C中有.cctor,而A没有,打开B,C的.cctor,可以看到它们都负责初始化本身的静态字段,如今首要来看它们的.ctor。

先看类C的.ctor:

 IL_0001: ldc.i4.3


 IL_0002: stfld      int32 ConsoleApplication1.C::z


 IL_0007: ldarg.0


 IL_0008: call       instance void ConsoleApplication1.B::.ctor()


 IL_000d: nop


 IL_000e: nop


 IL_000f: ldarg.0


 IL_0010: call       instance void ConsoleApplication1.C::m3()




可以看到:
在C被实例化时,它最先初始化在声明时同时赋值的字段(非静态),此处是将3赋给z,然后它会调用其基类的.ctor(),然后再调用本身的实例办法m3(),值得重视的是,在履行显式定义的机关办法体中的代码前,会先调用其基类的机关办法(创建基类的实例)。

再来看类B的.ctor(): 

 IL_0001: ldc.i4.2


 IL_0002: stfld      int32 ConsoleApplication1.B::y


 IL_0007: ldarg.0


 IL_0008: call       instance void ConsoleApplication1.A::.ctor()


 IL_000d: nop


 IL_000e: nop


 IL_000f: ldarg.0


 IL_0010: call       instance void ConsoleApplication1.B::m2()




同样,我们可以看到,在实例化B时,它会先把2赋给本身的y,然后再调用基类A的机关办法,最后再调用本身的实例办法m2()。

那A的.ctor()就不再看了,可以猜到它必然是在做如许的事:
1、 将1赋给实例的x字段;
2、 调用基类System.Object的机关办法.ctor来创建基类的实例;
3、 调用实例办法m1();

总结


1、.ctor是机关办法;
2、.cctor是类型初始化器,在C#中也就是静态机关函数;
3、当类C实例化时,会先对声明时就进行赋值的字段赋值,然后调用基类的机关函数,基类再以同样的办法机关本身,一向到顶层的System.Object,然后再回来履行C的显式机关办法中的代码,就是这么一个递归的过程。


参考材料


1、《Essential .NET》 Volume 1


原文:http://www.cnblogs.com/mouhong-lin/archive/2008/05/18/1201747.html



 

上海软件开发公司业务部:黄浦区重庆北路211号602室 | 上海软件开发公司技术部:松江区天云路259号| 上海软件开发公司综合部:松江区南期昌路346弄50号401室
上海软件开发 Copyright © 2005-2010 All Rights Reserved 电话:021-57616508  传真:57661889
沪ICP备05011021号