c#构造器的一点理解(三)
本章的重点是 类型构造器
本人的疑问 :
1 类型构造器是初始化类型的初始字段的,那么实际的应用场景是什么那?
2 在类型中,静态构造器,以及静态字段是用来做什么的那。
3 静态构造器在值类型和引用类中中非别如何使用,如何理解那!
下边的几个知识点是从书中(clr via c#)看到的
1 编译器不默认生成静态构造器,如果显式的生命,那么类型构造器只能生命一个static 的,private的,无参的构造器。 当类型第一次被访问的时候调用。
2 类型构造器只能是private的, 但是不能显示指定修饰符,如果指定了会报错,这样做的目的是为了防止程序员修改其访问属性。
3 值类型也可以声明类型构造器,但是不要这么做,因为值类型的类型构造器有的时候是不别调用的, 例如生命诚数组的时候 ?
那么为什么引用类型肯定会存在调用类型构造器的情况 ? -- 因为引用类型的数据类型,必须被实例化才能使用,如果没有实例化,那么就不能使用 ? 不知道这么理解是否正确。
4 类型构造器只能别执行一次。如果是多线程程序,那么如何保证类型只被执行一次。
这种情况需要一个互斥的相称同步锁 ? 这个代码是手工实现,还是clr已经实现了 ? 以后研究。
5 类型构造器可以实现单例模式。
6 类型构造器 不能互相引用,这样是错误的方法, 意识就是classa的类型构造器 和classb的类型构造器不能互相引用。
7 类型构造器如果有异常,那么这个类就不能使用。 代码如下:
sealed class baseClass { public void Test() { Console.WriteLine("基类") ; } static baseClass() //只能是无参,statci的,private的,但是private还不能显示指定。 { throw new Exception("") ; //有这句代码,使用类型的的时候就报错 ,意思也就是类型构造器不能有错误,有了错误,那么整个类型就不能使用了。 Console.WriteLine("类型构造器") ; } }类型构造器的常规用途就是初始化 静态字段。
而且提供了一种简便的语法结构。
private static Int32 i = 5 ; //值类型中的字段是不能使用这种结构的,但是值类型的静态字段是可以这么用的。
struct someTypa { static int a = 5 ; }但是
struct someTypa { int a = 5 ; }这么些就是错误的 为什么那 ? 因为第二种情况是值类型无参构造函数的写法,但是值类型又不允许有无参构造器。所以是错误的
第一种情况为什么是正确的那 ? 类型构造器本身就是为了处理静态字段而生的,所以这么做是正确的。 -- 融会贯通了,很多东西都是很好理解的,哈哈,我入门了,oye
8 类型构造器不应调用基类的类型构造器,因为没有继承基类的静态字段 ? 类型的静态字段不能被继承 ?
我的理解是,因为类型构造器是private的,所以不能被继承。
9 当访问类型构造器的时候同时能访问所以基类的类型构造器。 类型实现的接口也需要访问类型构造器 ? clr不支持这个做饭。
10 卸载类型的时候执行一些代码 clr同样不支持。但是可以使用变通的方式来实现 ?
9 10 两种情况,以后慢慢研究。
下边的代码 是上边情况的验证代码 以及注释 :
using System; using System.Data; using System.Text; namespace myStu { /* 值类型 最好不要定义类型构造器 引用类型可以定义类型构造器,但是只能是一个。 本程序主要是为了加深类型构造器而写的一个学习用的程序。 */ class programe { static void Main(string[] arg) { try { sonclass obj = new sonclass() ; //首先调用类型构造器。 //还有一个疑问,为什么这里还要调用父类的类型构造器 //是否可以这么理解, //首先的调用子类的类型构造器, //然后调用基类的实例构造器钱,这个时候出发了 基类的类型构造器。 //调用基类的实例构造器 //调用子类的实例构造器 . 能把这句话搞清楚就说明你进步了。哈哈 obj.Test() ; sonclass obj1 = new sonclass() ; //这里就不调用类型构造器了。 obj1.Test() ; } catch (Exception err) { Console.WriteLine(err.Message); } } } class baseClass { public static Int32 i = 5 ; public void Test() { Console.WriteLine("测试的动作") ; } public baseClass() { Console.WriteLine("基类的实例构造器"); } static baseClass() //只能是无参,statci的,private的,但是private还不能显示指定。 { //throw new Exception("") ; //有这句代码,使用类型的的时候就报错 ,意思也就是类型构造器不能有错误,有了错误,那么整个类型就不能使用了。 Console.WriteLine("基类的类型构造器") ; } } class sonclass :baseClass { static sonclass () { Console.WriteLine("子类类型构造器") ; } public sonclass() { Console.WriteLine("子类的实例构造器"); } } struct someTypa { static int a = 5 ; } }
类型构造器的调用 以及性能问题
1 类型构造器的调用是线程安全的。 只能被调用一次。 这些的实现是有clr来决定的。
2 什么时候类型构造器可以被调用。
精确语义 : 引用类型被实例化之前
访问非继承成员和字段之前(这种情况应该是不调用构造函数就有了类型实例的情况)。
字段初始化钱语义
访问非继承静态字段之前被访问。
做好的方案当然是是用第二种情况了,但是在c#我们怎么决定是使用第一种情况还是使用第二种情况那,
这个可以通过隐式实现类型构造器,或者是显示实现构造器来进行区别,这个是在c#层面说的,
在clr层面来说,是在元数据表中是够调价 beforSatticfielsini 标记来进行区分的。
这里现在还不是很明白,需要以后在进行详细研究。