初始华数据
使用初始化列表:

使用特殊的语法允许一个构造函数调用另一个构造函数重载。
目的:可以用来避免重复的初始化代码。如下面的构造函数:
class Date


{
public Date( )


{
ccyy = 1970;
mm = 1;
dd = 1;
}
public Date(int year, int month, int day)


{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
} 其中的ccyy,mm,dd赋值重复。这样做的缺点是:如过要改变ccyy,mm,dd的值,需要更改2处。
避免以上问题的常规方法是:
class Date


{
public Date( )


{
Init(1970, 1, 1);
}
public Date(int year, int month, int day)


{
Init(day, month, year);
}
private void Init(int year, int month, int day)


{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
} 这样做可以解决重复代码赋值的问题,但是无法解决处理只读字段的问题。C# 提供的方法是:
使用初始化列表。
初始化列表允许在同一个类中,一个构造函数调用另一个构造重载。
class Date


{
public Date( ) : this(1970, 1, 1)


{
}
public Date(int year, int month, int day)


{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
} 使用初始列表的限制:
1.不能使用非构造函数使用初始化列表;
class Point


{

public Point(int x, int y)
{
}
// Compile-time error

public void Init( ) : this(0, 0)
{ }
} 2.不允许构造函数使用初始列表调用自身;
class Point


{
// Compile-time error

public Point(int x, int y) : this(x, y)
{ }
} 3.不允许在建立构造函数参数的表达式中使用关键字this;
class Point


{
// Compile-time error

public Point( ) : this(X(this), Y(this))
{ }

public Point(int x, int y)
{
}

private static int X(Point p)
{
}

private static int Y(Point p)
{
}
}
声明只读变量和常数:
可以声明只读变量:
readonly int nLoopCount = 10; 如果在run-time更改nLoopCount的值,将导致错误。
常量:指它的数值不发生变化;
const int speedLimit = 55; 常量的值可以同其它常量值有关,如:
const int speedUnLimit = speedLimit*2;
初始化只读字段:

不允许重复赋值的字段可以定义为只读字段。
初始化只读字段有3种方法:
1.使用只读字段的默认值;
系统默认的构造函数会初始化所有的字段,不论字段是否是只读。如果自己定义了构造函数,但是不显示的初始化各个字段,编译器也会初始化各个字段。
class SourceFile


{

public SourceFile( )
{ }
public readonly ArrayList lines;
}
class Test


{
static void Main( )


{
SourceFile src = new SourceFile( );
Console.WriteLine(src.lines == null); // Still true
}
}
2.在构造函数中初始化;
class SourceFile


{
public SourceFile( )


{
lines = new ArrayList( );
}
private readonly ArrayList lines;
}
这样做的好处是,可以使用构造函数的参数初始化只读字段:
class SourceFile


{
public SourceFile(int suggestedSize )


{
lines = new ArrayList(suggestedSize);
}
private readonly ArrayList lines;
}
3.在声明只读字段时定义;
class SourceFile


{
public SourceFile( )


{


}
private readonly ArrayList lines = new ArrayList( );
}
上面的声明,编译器编译时,还会把初始化部分放在构造函数中。
给结构声明构造函数:

结构的构造函数语法同类的构造函数语法相同:
struct Point


{

public Point(int x, int y)
{
}


} 声明结构的构造函数的限制:
1.编译器会自动建立一个默认的构造函数;
2.你不能够声明默认的构造函数;
3.不能生命Protected的构造函数;
4.必须初始化所有字段;
编译器会自动建立一个默认的构造函数:
不论你是否已经建了1个构造函数,编译器会自动生成一个默认的构造函数。这点与类不同,在类中,如果建立了自己的构造函数,编译器是不会再增加构造函数的。
在结构的默认的构造函数中,所有字段被初始化为0,false,null.
struct SPoint


{

public SPoint(int x, int y)
{
}


static void Main( )


{
// Okay
SPoint p = new SPoint( );
}
}
class CPoint


{

public CPoint(int x, int y)
{
}


static void Main( )


{
// Compile-time error
CPoint p = new CPoint( );
}
} 说明,其中的SPoint p=new SPoint(),在堆栈上建立了新的Struct并初始化了所有字段,这点不可改变。
代码SPoint p;只是在堆栈上建立struct ,并不初始化字段。
struct SPoint


{
public int x, y;


static void Main( )


{
SPoint p1;
Console.WriteLine(p1.x); // Compile-time error
SPoint p2;
p2.x = 0;
Console.WriteLine(p2.x); // Okay
}
} 不允许在结构中声明默认构造函数:
原因是:编译器会自动建立这个默认的构造函数,如过再次建立,将会出现代码重复。
class CPoint


{
// Okay because CPoint is a class

public CPoint( )
{
}


}
struct SPoint


{
// Compile-time error because SPoint is a struct

public SPoint( )
{
}


}
我们可以建立带有参数的构造函数,这时,我们需要给各个字段手工赋值。
不允许在结构中建立Protected的构造函数:
原因:结构不允许继承,所以protected就没有意义了。
class CPoint


{
// Okay

protected CPoint(int x, int y)
{
}
}
struct SPoint


{
// Compile-time error

protected SPoint(int x, int y)
{ .. . }
}
所有字段必须赋初始值:
在类中,如果在构造函数中不给字段赋值,那么编译器可以保证所有字段还有默认值。
class CPoint


{
private int x, y;

public CPoint(int x, int y)
{ /**//*nothing*/ }
// Okay. Compiler ensures that x and y are initialized to
// zero.
} 但是在结构中,如果这样做,会发生编译错误:
struct SPoint1 // Okay: initialized when declared


{
private int x = 0, y = 0;

public SPoint1(int x, int y)
{ }
}
struct SPoint2 // Okay: initialized in constructor


{
private int x, y;
public SPoint2(int x, int y)


{
this.x = x;
this.y = y;
}
}
struct SPoint3 // Compile-time error


{
private int x, y;

public SPoint3(int x, int y)
{ }
} 使用Private修饰的构造函数:

在数学函数中,使用静态和实例方法的对照:
使用实例:
class Cumbersome


{
static void Main( )


{
Math m = new Math( );
double answer;
answer = m.Cos(42.0);
// Or
answer = new Math( ).Cos(42.0);
}
} 静态方法:
class Math


{

public static double Cos(double x)
{
}

public static double Sin(double x)
{
}
}
class LessCumbersome


{
static void Main( )


{
double answer = Math.Cos(42.0);
}
} 静态方法更加简洁些,因为不需要建立实例,速度更快些。
但是还存在一个问题,编译器会建立默认构造函数,是Public的,但是我们只需要使用静态的方法,从不使用这个默认的构造函数。
存在2个方法解决:
1.把Math声明为Abstract的类;
2.建立Private的构造函数;通过建立Private的构造函数,可以阻止编译器建立构造函数,因为是Private的,可以阻止Math建立实例,同样可以阻止使Math成为基类。
使用静态的构造函数:
构造函数的实例确保对象在使用前的状态是正常的,而静态的构造函数可以确保类在使用前的状态是正常的。
在run-time加载类
C# 是动态语言,当CLR运行.Net程序时,经常遇到没有加载到内存的类,这时,执行将暂停,动态加载所需类,然后继续执行。
C#确保类在使用前被初始化,这个由静态构造函数完成。
1.类的静态构造函数在类的任何实例建立前执行;
2.静态构造函数在任何静态成员建立饮用前执行;
3.静态构造函数在任何其它衍生类的静态构造函数执行前执行;
4.静态构造函数只执行一次;
静态构造函数的最常用的用途是初始化静态字段。
使用静态构造函数的限制:
1.不允许调用静态构造函数;
2.不允许使用修饰符来建立静态构造函数;
3.不允许静态构造函数带任何参数;
4.不允许在静态构造函数中使用this关键字;
参考:MSDN Training
Introduction to C# Programming
for the Microsoft® .NET Platform
(Prerelease)
Workbook
Course Number: 2124A