天天看点

黑马程序员_类

------- Windows Phone 7手机开发、.Net培训、期待与您交流! ------- 

为了便于复杂程序开发,开发人员将数据和与之相关的运算打包到一起,统一考虑,从而形成了类。类实际就是数据和相关处理的代码的封装体。它也构成了面向对象编程的核心。

类的概念

类(class)是一种数据结构,它可以包含数据成员、函数成员和嵌套类型。

类支持继承,继承是一种机制,它使派生类可以对基类进行扩展和专用化。C#应用程序一般是由编程者自定义的类和.NET Framework的类组成。

类声明

类和变量一样,在使用之前必须声明。声明类需要使用class关键字

声明名称为Program的类。

public class Program            //声明类Program

{   

}

类的访问权限

不同的类需要有不同的访问权限,因此使用类修饰符来限定类。C#用多种修饰符来表达类的不同性质。类修饰符放在class关键字的前面,它包括new、public、protected、internal、private、abstract和sealed 7个关键字。其中,public、protected、internal和private修饰符控制类的可访问性。

它们的意义具体说明如下:

public修饰符表示该类是公开的,访问不受限制。

protected修饰符表示该类只能是本身或其派生的类访问。

internal修饰符表示该类只能是在当前应用程序中访问。

private修饰符表示该类只能是本身访问。

abstract修饰符指定类为抽象类;

sealed修饰符指定类为密封类,即它不能被继承。

声明一个名称为Test的抽象类,并在该类中声明一个名称为Function()的抽象方法。

abstract class Test           //声明抽象类Test

{   

      abstract public void Function();                  

     //抽象方法,方法不包括具体实现

}

注意:抽象类不能被实例化,它一般作为其他类的基类,也不能被密封。

声明一个名称为Class1的密封类,并在该类中声明一个名称为Fun()的方法。

sealed class Class1                 //声明密封类Class1

{   

      public void Fun()

            {

            }             //方法

}

注意:密封类不能作为基类,也不能作为抽象类。因此,不能从密封类派生新的类。

new修饰符

在继承关系中,如果子类和父类拥有同名的方法,编译器会发出警告。为了避免这种警告,需要在子类定义该方法的时候,使用new进行修饰。

new修饰符用于显式隐藏从基类继承的成员,并用派生类的方法替换基类的方法。如果在不是继承类声明中使用new修饰符,则会生成警告。

声明两个类:Class1和Class2。其中,Class2类是Class1类的派生类。Class1类和Class2类都声明一个名称x的静态字段,并且Class2类使用new修饰符有意隐藏继承的静态字段x。

public class Class1

{

     public static int x = 55;

     public static int  y=22;

}

public class Class2 : Class1

{

     new public static int x = 100;   //使用 new 修饰符声明一个静态字段

     static void Main()

    {

          Console.WriteLine(x);   // Class2类中的x

          Console.WriteLine("Class1="+Class1.x);

          Console.WriteLine(y);

          Console.WriteLine();

    }

}

继承类

在程序开发中,有一些类是通用的。就像学生类、教师类,都是基于人这个类,都有姓名、性别、年龄这些成员。通过使用继承可以创建通用类,该类定义一组相关对象所共有的特征。然后,该类可以被其他更具体的类继承,再添加一些特有的成员。类类型支持继承(inherit)。继承是一种机制,它使派生类可以对基类进行扩展和专用化。即一个类可以从另外一个类继承而来。

声明两个类:Class1和Class2类。其中,Class2类从Class1类直接继承而来,Class1类被称为Class2类的直接基类,Class2类为Class1类的派生类。

public class Class1 

{

     public void F() { }                     //Class1类的方法

}

public class Class2 : Class1             //继承于Class1类,包括它的成员

{

}

Class2类继承于Class1类,即隐式地把Class1类的成员也当作自己的成员(除了Class1类的构造函数和析构函数之外)。因此,Class2类的成员也包括F()方法。

类继承具有以下5个特点。

继承是可传递的。如果C类从B类派生,而B类从A类派生,那么C类就会既继承在B类中声明的成员,又继承在A类中声明的成员(除了A类的构造函数和析构函数之外)。

继承是可扩展的。派生类能够扩展它的直接基类,而且能够添加新的成员,但是不能移除继承成员的定义。

基类成员可隐藏。派生类可以通过声明具有相同名称或签名的新成员来隐藏那个被继承的成员(使用new修饰符)。

父类与子类类型可转换。存在一个从派生类类型到它的任一基类类型的隐式转换。

子类可重载父类的成员。类可以声明虚的方法、属性和索引器,而派生类可以重写这些函数成员的实现。这种特征被称为类的“多态性行为”特征。

类、对象和实例化

类是从对象抽象出来的。要实现重用,必须由类构建出对应的对象。这个过程称为实例化。实例化是一种操作,它可以为类的实例分配内存。

声明名称为Program的类,并创建Program类的一个实例p,然后使用new操作为p实例化。

public class Program         //定义一个公有类Program

{

}

Program p;                      //定义一个类Program的对象p

p = new Program();            //将类Program的对象p实例化

“public class Program{…}”代码声明名称为Program的类,即Program是一个类。p是Program类的一个实例,也称为对象,此时,p的值为null。“p = new Program ()”表达式将p实例化,此时,p的值不为null,它可以被引用或访问。

类的组成

类可以包含多种成员,分为两大类:

数据成员和函数成员。其中,数据成员包括常量和字段;

函数成员包括方法、属性、事件、索引器、运算符、实例构造函数、析构函数和该类的静态构造函数。

常量:用来表示常数值。

字段:类的变量。

方法:是包含一系列语句的代码块,通过这些代码块能够实现预先定义的计算或操作。

事件:一种使对象或类能够提供通知的成员。客户端可以通过提供事件处理程序(event handler)为相应的事件添加可执行代码。

属性:用于访问对象或类的特性的成员。

索引器:是一种含有参数的属性,又称为含参属性。它提供索引的方式来访问对象,即与数组的访问方式相同。

运算符:定义表达式运算符,通过它可以对该类的实例进行运算。

实例构造函数:不使用static修饰符,用于实现初始化该类的实例所需的操作。

析构函数:一种用于实现销毁类实例所需操作的成员。静态构造函数:使用static修饰符,用于实现初始化该类自身所需的操作。类型:该类的局部类型。

常量

常量(constant)是使用一个标识符来代替一个不变的值。例如使用PI代替圆周率。

使用常量有两个好处:

一是使程序易于维护、修改;

二是使程序的安全性更好。

常量的类型必须为sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型。

在声明常量时,需要使用const关键字。但是,常量必须在定义时就赋值。在定义完常量后,在后面的编程中就不允许对常量进行重新赋值。

声明名称为pi的、类型为float的常量。

const float pi = 3.14f;              //声明float型的常量pi,并为它赋初值

如果使用一个const关键字同时声明多个常量,那么常量之间需要使用,(逗号)分隔。

声明3个类型为int的常量:i、j和k,它们的值分别为1、2和3。

const int i = 1, j = 2, k = 3;    //声明类型为int的三个常量i,j,k,并为其赋初值

声明了3个类型为int的常量:i、j和k,它们的值分别为1、2和3。

等价于下列语句:

const int i = 1;

const int j = 2;

const int k = 3;

如果一个常量的值依赖于其他常量的值,且这种依赖关系不是循环的,那么编译器会自动按照一定的顺序计算所有常量的值。

声明2个类:Class1和Class2。Class1类包括2个常量:I和J;Class2类包含一个常量:K。I常量的值依赖于K常量,K常量的值依赖于J常量。因此,编译器在计算这3个常量的值时,首先计算J常量的值,然后计算K常量的值,最后计算I常量的值。

public class Class1

{

     public const int I = Class2.K+1;

     public const int J = 2;

}

public class Class2

{

     public const int k = Class1.J+2;

}

class Program

{

     Console.WriteLine("I+"+Class1.I);

     Console.WriteLine("J+"+Class1.J);

     Console.WriteLine("K+"+Class2.K);

     Console.WriteLine();

}

编译器首先计算J常量的值为2,然后计算K常量的值为4,最后计算I常量的值为5。

字段

字段表示类和对象中的数据成员。它是类中的变量。

声明2个字段:i和j。i字段没有显式被赋值,j字段显式被赋值为20。

int i;               //声明一个字段i

int j = 20;      //声明一个字段j并为它赋初值20

如果在同一个语句中同时声明多个字段,那么字段之间需要使用,(逗号)分隔。

声明3个类型为int的字段:i、j和k。其中,k字段的值为20。

int i,j,k = 20;                   //i和j字段的值为0,k字段的值为20

根据字段的修饰方式,可以把字段分为以下4种。

静态字段:使用static修饰,对应于静态变量。

实例字段:不使用static修饰,对应于实例变量。  

只读字段:使用readonly修饰。

易失字段:使用volatile修饰。该类型的字段很少使用。

在Program类中声明4个类型均为int的字段:i、j、k和m。其中,i为静态字段,它的值为20;j为实例字段,它的值为100;k为只读字段,它的值为1;m为静态只读字段,它的值为15。

public class Program

{   

static int i = 20;                           //静态字段   

int j = 100;                                  //实例字段   

readonly int k = 1;                          //只读字段   

static readonly int m = 15;                //静态只读字段

}

静态字段和实例字段最大的差别在于:静态字段不属于类的特定实例,而实例字段是属于其所在的实例,如i字段不属于Program类的某一个实例。当应用程序被编译时,编译器就会为应用程序的所有静态字段分配相应的存储位置。因此,对于一个应用程序而言,每一个静态字段都只有一个存储位置。

创建Program类的2个实例:p1和p2。p1和p2实例都为j字段(为实例字段)分配各自的存储位置。而p1和p2实例的i字段(为静态字段)都引用同一个存储位置(由编译器决定)。

Program p1=new Program ();

Program p2=new Program ();

常量和只读字段最大的差别在于:常量的值在编译时确定,而只读字段的值在运行时确定。如果要给只读字段赋值,只有在声明该只读字段的语句中.k字段就在其被声明时并赋值为1

方法

方法(method)表示类和对象中的操作。它是包含一系列语句的代码块,通过这些代码块能够实现预先定义的计算或操作。方法一般声明在类或结构中,由访问级别、返回值、方法名称、方法参数和方法体组成。其中,访问级别、返回值、方法名称和方法参数统称为方法的“签名”。方法参数包括在小括弧“()”中,多个参数使用“,”(逗号)分隔。如果括弧中为空,则表示该方法不需要参数。

在Program类中声明一个方法。该方法的签名为“public int Function(int a,int b)”,方法名称为Function,访问级别为public,返回值类型为int,方法参数为“int a,int b”,方法体为紧跟该方法签名之后的两个“{}”之间的代码。

class Program

{

     public int Function(int a, int b)

     {

           return a+b;

     }

     static void Main(string[] arge)

     {

            int  I=2,J=3,k;

            Program p = new program();

            k=p.Function(I,J);

            Console.WriteLine("k = "+k);

            Console.WriteLine();

     }

}

方法参数

方法参数的使用可以提高代码的重用性。它实现的是在调用方法通过实参给方法传递数据,然后方法执行相应的操作,再返回调用方。方法参数可以包含一个或多个参数。如果存在多个参数,则参数之间使用逗号分隔。方法参数包括以下4种参数。

值参数:声明参数时不带任何修饰符,如int i等。

引用参数:声明参数时带有ref修饰符,如ref int i等。

输出参数:声明参数时带有out修饰符,如out int i等。

参数数组:声明参数时带有params修饰符,如params int[] array等。

一个值参数相当于一个局部变量,它的值来源于该方法调用时所提供的参数的值。引用参数不创建新的存储位置,而是使用其基础变量(作为方法参数的变量)的存储位置。

注意:在方法被调用时,引用参数也必须添加ref关键字,且基础变量必须是明确赋值的。

输出参数也不创建新的存储位置,而是使用其基础变量(作为方法参数的变量)的存储位置。

注意:在方法被调用时,输出参数也必须添加out关键字,且在方法返回之前,必须为该参数明确赋值。

参数数组必须为一维数组,且必须为方法的最后一个参数,它不能同时和ref或out修饰符使用。

声明一个签名为“public int F(int i,int j,ref int c,out int sum,params int[] args)”的方法。该方法的方法参数为“int i,int j,ref int c,out int sum,params int[] args”。i和j为值参数,c为引用参数,sum为输出参数,args为参数数组。

public int F(int i,int j,ref int c,out int sum,params int[] args)

}

下面调用F(int i,int j,ref int c,out int sum,params int[] args)方法。i、j、c、sum和args参数的值分别为10、20、c、sum和args。其中,c和sum变量为int类型,args变量为元素类型为int的数组,且包括3个元素:1、2和3.

int c = 0,sum;

int[] args = new int[]{1,2,3};

int result = F(10,20,ref c,out sum, args);           //调用F()方法

参数数组比较特殊,它可以使用数组变量或多个元素变量直接作为它的参数来传递。如果变量为数组,则把该数组变量作为值参数进行传递。如果是多个元素变量,则为这些元素变量创建一个数组,然后将该数组作为值参数进行传递。因此,参数数组可以匹配一个数组变量,或者由0个或1个或多个变量组成的列表。

注意:不管是数组变量,还是元素组成的列表,它们的元素类型必须能够隐式转换为参数数组的元素类型。

声明一个签名为“public int Print(params int[] args)”的方法。该方法只包含一个参数数组args,其元素类型为int。Print(params int[] args)方法将args数组中的每一个值输出到控制台,最后还输出一个换行符号。然后调用Print(params int[] args)方法3次。第1次调用时使用了数组arr作为其参数,第2次调用时使用“1,2,3”作为其参数,第3次调用时未使用任何参数。

class program

{

   public static void Print(params int[] args)

   {

          Console.Write("Values");

          foreach (int i in args)

          {

               Console.WriteLine(i + " ");

          }

          Console.WriteLine();

   }

   static void Main(string[] args)

   {

       int[] arr = new arr{1,2,3};

       Print(arr);

       Print(1,2,3);

       Print();

       Console.WriteLine();

   }

}

当第1次调用时使用了arr作为其参数,它将arr数组作为值参数传递,因此输出arr数组中各个元素的值。

当第2次调用时,该方法自动为这3个值创建一个元素数量为3、元素类型为int的数组,然后将该数组作为值参数传递。

当第3次调用时,该方法自动创建一个元素数量为空的、元素类型为int的数组,然后将该数组作为值参数传递。

注意:实际上,“ Print(1,2,3);  ” 等效于“ Print(new int[]{1,2,3}); ”  ,

                           “ Print();  ” 等效于“ Print(new int[]{}); ”  。

静态方法和实例方法

静态方法是类的方法,每个类也有自己的操作,静态方法从类一创建好就开始存在。而实例方法是对象的方法,只能通过对象去调用。静态方法和实例方法与静态变量和实例变量比较相似,静态方法也是使用static修饰符,而实例方法不使用static修饰符。静态方法属于某一个类,实例方法属于类的某一个实例。

下面在Program类中声明两个方法:F1和F2。其中,F1为静态方法,F2为实例方法。然后分别调用Program类的F1和F2。在调用F1方法时,直接使用Program类调用F1方法。在调用F2方法时,首先为Program类创建一个实例p,然后通过p实例调用F2方法。

class Program

{

     public static int F1()

     {

           Console.WriteLine("调用静态方法 F1 ");

          return 1;

     }

     public int F2()

     {

          Console.WriteLine("调用实例方法 F2 ");

          return 2;

     }

     static void Main(string[] args)

     {

          int r1 = new Program.F1();

          Console.WriteLine("r1 = "+r1);

          Program p = new Program();

          int r2 = p.F2();

          Console.WriteLine("r2 = "+r2);

          Console.WriteLine();

     }

}

虚方法和重写方法

虚方法的出现是为了实现基类可以调用派生类的方法。重写虚方法也不是必须的操作。如果派生类没有重写虚方法,那么将使用基类的虚方法。若在一个实例方法的声明中含有virtual修饰符,则称该方法为虚方法,否则称为非虚方法。相对于非虚方法而言,虚方法可以由派生类来实现。在派生类中实现(使用override关键字)虚方法的过程被称为重写方法。简而言之,虚方法可以被派生类重写的,而非虚方法却不能被重写。

程序在Program类中声明两个方法:P1和P2。其中,P1为虚方法,P2为非虚方法。然后再创建一个Test类,它为Program类的派生类。Test类也声明两个方法:P1和P2。其中,P1使用override关键字重写Program类中的P1方法,P2为非虚方法。

public class Program

{

   public Virtual void P1()        //虚方法

   {

      Console.WriteLine("Program.P1");

   }

   public void P2()                     //非虚方法

   {

      Console.WriteLine("Program.P2");

   }

}

public class Test : Program

{

      public override void P1()      //重写了Porgram类的虚方法 P1

      {

         Console.WriteLine("Test .P1");

      }

      public void P2()                     //非虚方法 P2

      {

           Console.WriteLine("Test.P2")

      }

}

public class T

{

   static void Main()

   {

      Test t = new Test();

      Porgram p = new Porgram();

      Porgram program;

      program = p;

      program.P1();

      program = t;

      program.P1();

      program.P2();

     Console.WriteLine();

   }

}

代码“program.P1();”中调用了子类的重写的方法P1(),而子类中P2方法是非虚方法。因此“program.P2();”调用的是基类的方法P2()。

密封方法

C#继承的功能很强大,但有时可能需要阻止某种继承。例如,有一个封装某些特定硬件设备的初始化操作的类,我们不希望让类的用户能够更改该设备的初始化方式,因为用户可能将设备设置错误。因此,通过使用sealed关键字可以很容易地防止类被继承。同样地,在方法的声明中添加关键字sealed,就可以防止任何该类的派生类重写该方法。当实例方法声明包含sealed修饰符时,称该方法为密封方法(sealed method)。在声明密封方法时,也必须同时添加override修饰符。

注意:使用sealed修饰符可以防止派生类进一步重写该方法。即密封方法不能被派生类重写。

创建一个Test2类,它为Program类的派生类。Test2类声明一个方法:F1。该方法使用override关键字重写Program类中的F1方法,并使用sealed修饰符把该方法设置为密封方法。

public class Test2:Program

{

public sealed override void P1()      //重写了Program类的虚方法P1,并添加了sealed修饰符   

{       

 Console.WriteLine("Test2.P1");       //显示“Test2.P1”字符串   

 }

}

抽象方法

有时我们想要创建一个方法,它只定义其派生类共享的通用化形式,而让派生类去实现具体内容。我们需要某种方式来确保派生类实际上重写了方法。对于这个问题,C#的解决方法是使用抽象方法。当实例方法声明包含abstract修饰符时,称该方法为抽象方法(abstract method)。抽象方法不提供该方法的实现,它的方法体仅仅只包含一个;(分号)。

注意:抽象方法只能创建在抽象类中,且默认为虚方法。但是,在声明抽象方法时,不能使用virtual修饰符。

创建一个抽象类Program,并在该类中声明一个抽象方法Print()。该方法不包括其实际实现。

public abstract class Program

{   

public abstract void Print();              //Print()方法为抽象方法

}

属性

属性(property)是C#语言所特有的一种机制,它可以用于访问对象或类的特性的成员。属性和字段非常相似,而且访问属性和字段的语法相同。但是,属性不表示存储位置(字段表示一个存储位置)。属性通过一种被称为访问器的机制来获取或修改其值。其中,获取属性的值的访问器为称为get访问器,修改属性的值的访问器被称为set访问器。

如果属性只包含get访问器,则称该属性为只读属性。

如果属性只包含set访问器,则称该属性为只写属性。

如果属性既包含get访问器,又包含set访问器,则称该属性为读写属性。

get访问器和set访问器的具体说明如下:

get访问器相当于一个无参数方法,且该访问的返回值的类型和属性的类型相同。在get访问器中,必须包含return语句,返回该属性的值。

set访问器相当于一个返回类型为void的方法,且该方法只有一个参数,参数的类型和属性的类型相同。特别地,该方法的参数名称始终约定为value。

声明一个类型为string、名称为Name的属性。该属性包含get和set访问器。get访问器用来获取name私有变量的值,set访问器用来设置name私有变量的值。

public class Porgram

{

   private string name;     //声明name字段

   public string Name

   {

      get { return name ;}

      set { name = value ;}

   }

   static void Main()

   {

      Porgram p = new Program();

      p.Name = "小明";

      string name =  p.Name;           //调用 get 访问器

      Console.WriteLine(name);

      Console.ReadLine();

   }

}

如果在声明属性时,使用了static修饰符,则称该属性为静态属性,否则称该属性为实例属性。静态属性与实例属性的差别和静态字段与实例字段的差别相似。

注意:value为set访问器的隐式参数名称,这是C#语言的一种约定。因此,value变量始终表示为set访问器的值,即用户设置的值。且set访问器中不能包含“return 语句”的表达式。

索引器

在程序开发中,我们有时会需要对类的字段批量地做某种操作,比如字段的赋值、遍历等。索引器允许按照与索引数组相同的方式索引对象。这样我们就可以使用循环语句,通过下标的改变访问所有的对象中的字段,简化了代码。而且使用索引器,并不妨碍我们使用点运算符来调用类的某个字段。声明索引器时,需要使用this关键字。

在Program类中声明一个索引器。该索引器可以获取或设置list数组(元素类型为string)的元素的值。另外,Program类在其构造函数(count为参数,它决定list数组的大小)中初始化list数组并赋值。然后创建Program类的一个实例p,并把p实例的list数组的初始化为长度等于count变量的值100的数组。然后调用p实例的索引器输出p实例的list数组的每一个元素。

public class Program

{

   private string[] list;

   public string this[index]        // 声明索引器

   {

       get { return list[index]; }     // 获取list数组中的元素

       set                                           //设置list元素的值

        {

            if(index >=1 && index<list.Length)

              {

                index = value;

              }

        }

    }

   public Program (int const)        // 构造函数

   {

       list = new string[const];

      for( int i=0; i<const ; i++)

      {

          list[i] = i.ToString;

      } 

   }

   static void Main()

   {

      int const = 100;

      Program p = new Program(const);

      for(int i=0;i<cont ;i++)

      {

           Console.Write(p[[i] + " ");

           if( i%10 == 0)

            {

                 Console.WriteLine();

            }

           Console.ReadLine();

       }

   }

}

虽然索引器也是一种属性,但是它和属性存在以下5点区别。

属性存在一个名称,而索引器由this关键字指定,即它所在类的签名标识。

属性可以是静态属性(即使用static修饰),而索引器始终是实例成员(即不能使用static修饰)。

属性可以通过成员来访问,而索引器必须通过其索引来访问其元素。

属性的get访问器是不带参数的方法,而索引器的get访问器为带有参数(索引器的索引)的方法。

属性的set访问器是仅仅带有一个value参数的方法,而索引器的set访问器是除了value参数之外还带有与索引相关的参数的方法。

注意:虽然索引器和数组比较相似,但是索引器不属于变量,因此,索引器的元素不能作为ref或out参数传递。

构造函数

构造函数是类的一种特定的方法,通常用来初始化新对象的数据成员,即设置数据成员的默认值。构造函数是在创建给定类型的对象时执行的类方法,它的名称和其所属类的名称相同。在任何时候,只要创建类,就会调用它的构造函数。如果开发人员没有为类显式提供构造函数,则默认情况下C#编译器将为该类创建一个默认的构造函数

在A类中声明两个构造函数:public A()和public A(int count)。

第一个构造函数不携带任何参数,它也不执行任何操作。

第二个构造函数携带类型int的count参数,它用来初始化list数组,并设置该数组每一个元素的值。

 public class A

 {

     private string[] list;        //元素类型为string的数组

     public A()                                         //构造函数

     {

     }

     public A(int count)                              //构造函数

     {

         list = new string[count];         //为list数组分配内存

         for(int i = 0; i < count; i++)      //为list数组的每一个元素赋值

         {

             list[i] = i.ToString();

         }

     }

 }

“A a1 = new A()”语句将调用A类的A()构造函数,并创建A类的实例a1。

“A a2 = new A(2000)”语句将调用A类的A(int count)构造函数,并创建A类的实例a2。

构造函数可以分为实例构造函数和静态构造函数。实例构造函数是不使用static修饰符的构造函数,而静态构造函数是使用static修饰符的构造函数。

实例构造函数

在程序中,类的字段需要赋初值。使用构造函数有两个重要的作用:

一是防止字段出现系统不合理的初始化;

二是更方便对字段进行初始化,简化代码。

实例构造函数是通过对象调用的,用于创建和初始化实例。实例构造函数在创建新对象时被调用,

public A()和public A(int count)构造函数都是属于实例构造函数。

如果一个类不包含任何实例构造函数,那么系统会自动地为该类提供一个默认实例构造函数。

默认构造函数调用该类的直接基类的无参数构造函数。

如果其基类没有可访问的无参数实例构造函数,则发生编译时错误。

如果实例构造函数使用private修饰符,那么该构造函数为私有构造函数。私有构造函数是一种特殊的实例构造函数。它通常用在只包含在静态成员的类中。如果欲设计一个类并且不希望该类被实例化,则只需在该类中声明一个空的私有实例构造函数即可。

注意:默认构造函数将类的数据成员初始化为其类型的默认值(如果存在数据成员)。

程序中声明一个名称为Program的类,该类不包括任何构造函数。并且该类还包括两个公开字段:name和age。

还声明了一个类Jack,该类包含两个公开静态字段:name和age,它们的值分别为Jack和20。

 public class Program

 {

     public string name;                //声明name字段

     public int age;                    //声明age字段

 }

 public class Jack

 {

     public static string name = "Jack";          //静态字段name

     public static int age = 20;                    //静态字段age

     private Jack()                                       //私有构造函数

     {    }

 }

Program类没有声明构造函数,那么系统会自动为该类添加一个默认构造函数,并设置name和age数据成员的值分别为null(string类型的默认值)和0(int类型的默认值)。Jack类包括了一个空的私有实例构造函数,该类不能被实例化。“Jack jack = new Jack()”表达式用来创建Jack类的实例会发生错误。

静态构造函数

类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。因此,静态构造函数用于初始化类的静态成员。

在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。它也可以用于执行仅需执行一次的特定操作。

注意:静态构造函数是不可继承的,而且不能被直接调用。类的静态构造函数在给定应用程序域中至多执行一次,它在第一次创建类的实例时或第一次引用类的任何静态成员时被调用。

声明名称为Program的类,并且该类还包括两个公开字段:name和age。其中,name字段为静态字段。该类包括一个静态构造函数Program(),并在该静态构造函数中输出“初始化Program”字符串。

另外,该类还包括一个静态方法Show(),并在该方法中输出“Program.Show()”字符串。然后调用Program类的静态方法Show()(第一次被调用),并在调用该方法的同时也调用Program类的静态构造函数Program ()。

public class Program

{

   public static string name;  //静态字段

   public int age;

   static Porgram()     

   {

      Console.WriteLine("初始化 Porgram ");

   }

   public static void Show()

   {

      Console.WriteLine("Porgram.Show");

   }

   static void Main()

   {

      Program.Show();

      Console.ReadLine();

   }

}

程序代码在调用Program类的静态方法Show()(第一次被调用)的同时也调用Program类的静态构造函数Program ()。

注意:Program类的静态构造函数Program ()是通过Program.Show()方法触发的。如果不是第一次调用Program类的Show()方法,则不会触发Program类的静态构造函数Program()。

静态构造函数具有以下5个特点。

静态构造函数一般用于初始化静态字段、只读字段的值。

静态构造函数既没有访问修饰符(它默认为私有的),也没有参数。声明静态构造函数时,需要添加static修饰符。

无法直接调用静态构造函数,也无法控制何时执行静态构造函数。

在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。

如果类中包含Main()方法,那么该类的静态构造函数将在调用Main()方法之前执行。如果类包含任何带有初始值设定项的静态字段,则在执行该类的静态构造函数时,先要按照文本顺序执行那些初始值设定项。

析构函数

计算机中的资源,使用完毕就应该释放掉,给别的程序使用。而析构函数就是手动释放类的实例占用的资源,并销毁该类的实例。类的构造函数用来初始化该类的实例,析构函数和类的构造函数恰恰相反。析构函数的名称和类的名称一样,并带有“~”字符。通常情况下不需要使用析构函数。

声明一个名称为Program的类,该类包含了一个析构函数,并在该析构函数中输出“销毁Program类的实例”字符串。

public class Program

{   

               ~Program()            //析构函数   

        {       

                 Console.WriteLine("销毁Program类的实例");   

        }

}

析构函数具有以下4个特点。

析构函数既没有修饰符,也没有参数。

无法调用析构函数。它们是被自动调用的。

只能对类使用析构函数,而且一个类只能有一个析构函数。

无法继承或重载析构函数。

事件

事件在某些操作发生时自动地发出通知。比如说新员工到岗,需要给他办理入职手续。入职手续有好几个内容,这时我们可以定义一个事件,将这些内容封装在一起。只要有新员工到岗,就执行一次事件。事件是一种使对象或类能够提供通知的成员。客户端可以通过提供事件处理程序为相应的事件添加可执行代码。类或对象可以通过事件向其他类或对象通知发生的相关事情。

一个类或对象可以事先向其他类或对象注册一个事件,然后在一定的时候引发该事件。如开发人员可以向在Windows窗体中的按钮注册一个事件,当用户单击该按钮时,将引发该已注册的事件。

------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------