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 标记来进行区分的。
   这里现在还不是很明白,需要以后在进行详细研究。




















posted @ 2012-01-03 23:21  sdgxboy  阅读(149)  评论(0编辑  收藏  举报