我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:双彩网 > 值调用 >

C构造器之实例构造器与类型

归档日期:06-01       文本归类:值调用      文章编辑:爱尚语录

  【IT168技术】构造器是允许将类型的实例化为良好的状态的一种特殊方法。

  构造引用类型对象时,在调用实例构造器之前,为对象分配的内存总是先被归零,构造器没有显式重写的所有字段保证只有一个0或null值。

  因为实例构造器不能被继承,类只有类自己定义的实例构造器,所以就不能用virtual,new,override,sealed,abstract修饰符来定义构造器。

  如果定义的类没有显式的定义一个构造器,编译器会默认的定义一个无参的构造器。在默认构造器的实现中,它只是简单的调用了基类的无参构造器。

  如果类的修饰符是abstract,那么编译器生成的默认构造器的可访问性就为proctected。

  一个类型可以定义一个或多个实例构造器,每个构造器都必须有不同的签名。而且可以有不同的可访问性。

  类的实例构造器在访问从基类继承的任何字段之前,必须首先调用基类的构造器。如果派生类的构造器没有显式调用一个基类构造器,编译器会自动生成对默认的基类构造器的调用。最终,System.Object的公共无参构造器会得到调用,这个构造器嘛都不干,直接返回。因为System.Object没有定义实例数据字段,所以它的构造器就没事干。

  在极少的情况下可以在不调用基类构造器的前提下创建一个类型的实例,一个典型的例子是Object的MemberwiseClone方法。该方法的作用是分配内存,初始化对象的附加字段(你应该记得吧,类型对象指针和同步块索引)

  宾果(不要在构造器中调用会影响所构造对象的任何虚方法,原因是假如这个虚方法在当前要实例化的类型的派生类型中进行了重写,就会调用重写的实现,但是在继承层次结构中,字段尚未完全初始化(派生类型的构造器还没有调用)。)

  privateInt32 x=5;//sometype的构造器把5储存在字段x,接着调用基类的构造函数。C#编译器提供了一个简化的语法。允许以内联的方式初始化实例字段。但在幕后

  }//编译器在为这3个构造器方法生成代码时,在每个方法开始的位置,都会包含用于初始化x,s,i的代码。在这些//代码初始化之后,编译器会插入对基类构造函数的调用,然后在插入自己的构造器代码。//在这里,即使没有显式的初始化i,也会保证i会被初始化为0.

  在上面的例子中,some类有3个构造器,所以编译器公生成3此初始化x,s,i的代码。如果有几个已初始化的实例字段和大量重载的构造器,方法可以考虑下面的方法:

  值类型(struct)构造器的工作方式与引用类型的截然不同,CLR总是允许创建值类型的实例,并且阻止不了值类型的实例化。所以值类型不需要构造器,编译器也根本不会为值类型生成默认的构造器。

  但是CLR允许为值类型定义构造器,但如果要执行定义的构造器,必须要显式的调用它们。

  publicPoint(intx1,inty1)//如果显式声明了构造函数,就必须要为值类型的所有字段赋值。这是因为为了生成“可验证”的代码,在访问值类型的任何一个字段之前,要对所有的字段进行赋值。

  publicPoint()//结构体不能包含显式的无参构造函数,这里会编译出错!

  {//实际上,即使值类型提供哦你了无参构造器,许多编译器都不会去生成代码自动调用它,为了执行值类型的无参构造器,开发人员必须显式调用值类型的构造器。

  }//C#编译器故意不允许值类型定义无参构造器,就是为了避免开发人员对这种构造器在什么时候调用产生迷茫,由于不能定义无参构造器,所以编译器永远不会生成自动调用它的代码。

  privatePoint p1, p2;//值类型的实例构造器只有在显式调用的时候才会执行,

  当一个值类型有很多字段时,如果一个一个的赋值会不会很麻烦呢。。下面是对值类型全部字段赋值的一个替代方案:

  在值类型中,this代表值类型本身的一个实例,用new创建类型的一个实例可以赋给this。在new的过程中,所有字段为0/null。在引用类型中,this被认为是只读的,不能赋值。

  也就是静态构造器,类构造器或者类型初始化器。类型构造器可用于接口(C#编译器不允许,CLR允许),引用类型和值类型。

  实例构造器的作用是设置类型的实例初始状态。对应的,类型构造器的作用是设置类型的初始状态。类型默认没有定义类型构造器。如果自己定义,也只能定义一个。类型构造器永远没有参数!

  staticSome()//可以看出,类型构造器类似于实例构造器,区别在于必须将它们标记为static。

  //类型构造器没有访问你修饰符,总是私有的,但是如果显式的将类型标记为private 编译器会显示:静态构造函数不允许出现访问修饰符。

  //之所以私有,是为了阻止任何用开发人员写的代码调用它,对类型构造器的调用总是由CLR负责的。

  类型构造器的调用比较麻烦,JIT编译器在编译一个方法时,会查看代码中都引用了那些类型。任何一个定义了类型构造器的类型,JIT编译器都会检查针对当前AppDomain,是否已经执行了这个类型的构造器。如果构造器从未执行,JIT编译器会在它的本地(native)代码中添加对类型构造器的一个调用。如果类型构造器已经执行,JIT编译器就不添加对它的调用,因为JIT编译器知道类型已经初始化了。

  现在,当方法被JIT编译完毕后,线程开始执行它,最终会执行到调用哪个类型构造器的代码。事实上,多个线程可能同时执行相同的方法。CLR希望确保在每个AppDomian(应用程序域)中,一个类型构造器只能执行一次,为了保证这点,在调用类型构造器时,调用线程要获取一个互斥同步锁。这样一来,在某一时间就会只用一个线程执行类型构造器中的代码了,第一个线程执行类型构造器中的代码,完事了第一个线程释放锁,当第一个线程离开构造器,正在等待的线程将被唤醒,然后发现类型构造器的代码已经被执行过,它就不会在执行这些代码,直接从构造器方法返回。

  类型构造器中的代码只能访问类型的静态字段。并且它的常规用途就是初始化这些字段。和上面的实例字段一样,C#同样提供了一个简单的语法来初始化类型的静态字段。

  类型构造器不应调用基类型的类型构造器,因为类型不可能有静态字段是从基类型分享或继承的。

  //jit编译器优化调用BeforeFileldInit的类型构造器的代码,使它在循环之前执行。

  //jit编译器在这里生成调用Precise类的类型构造器的代码,所以在每次循环迭代,都要核实一遍是否需要调用构造器。

  //这个方法被jit编译时,BeforeFieldInit和Precise类的类型构造器已经被执行,所以这个方法的代码中,不会在生成对这些构造器的调用,它运行的更快。

  //由于类中显式定义了类型的构造器,所以没有用BeforefieldInit来标记定义

  C#编译器如果看到一个类(BeforeFieldInit)包含进行了内联初始化的静态字段,会在类型的类型定义表中生成一个添加了BeforeFieldInit元数据标记的记录项,

  c#编译器如果看到一个类(Precise)包含显式的类型构造器,就不会添加BeforeFieldInit元数据标记了。它的基本原理是:静态字段只要在访问之前初始化就可以了,具体什么时候无所谓。而显式类型构造器可能

本文链接:http://hotel-lermoos.com/zhidiaoyong/6.html