对构造函数的描述 II

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

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

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(
197011);
}

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(197011)
{
}

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(00{ }
}

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

posted on 2005-07-04 09:58  Pierce  阅读(556)  评论(0)    收藏  举报

导航