It计算机课件 C#课程讲义_第1页
It计算机课件 C#课程讲义_第2页
It计算机课件 C#课程讲义_第3页
It计算机课件 C#课程讲义_第4页
It计算机课件 C#课程讲义_第5页
已阅读5页,还剩63页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C#课程讲义

——杜浦(2005年)

基础知识

C#所属的.NetFramework是微软件为开发应用程序并管理其运行时执行而创建的一个

革命性的新平台。除了开发工具——如崭新的C#语言和原有语言的最新版本(包括Visual

Basic、C++和Jscript).NETFramework还有两个主要组成部分:一个称为公共语言运

行时(CLR)的运行时环境(CLR在很多功能上类似于Java虚拟机),和一个提供在Windows

平台上开发Windows应用程序所需的几乎所有常见功能的很大的类库。需要强调的一点是,。

NETFramework本身不是一个操作系统,但它以操作系统为基础。现在,.NET惟•实现是

基于Windows系统的,但其他实现(优其是基于Linux的)已经在开发过程中。在这些实

现中也将包括C#编译器。

.NETFramework有各种版本。要运行.NET应用程序,宿主计算机必须安装.NET。对于

客户端,如Windows应用程序,需要安装Framework的一个可再发布的精简版本,以保证

客户端能够运行该程序。这个版本的.NET可以安装在Windows9x/ME机器上,并能利用任

何文本编辑器编写和编译C#程序,而正规的开发工作要求安装完全版本的.NET软件开发工

具包(SDK),这个版本的.NET可以在WindowsNT*2000或XP上运行。

最后,专业的开发工作还要求有一个具备高度代码、智能感知和自动完成等功能的集成

开发环境(IDE)oC#开发的标准IDE是VisualStudio.NET(VS.NET),它是为编写.NET应用

程序专门设计的,能为Windows应用程序和Windows服务这样的工程生成许多标准的基础

代码。

公共语言运行时

是.NETFramework的真正核心。CLR管理代码在运行时的执行。C#编译器不是把程序

编译为本机代码,而是编译为一种称为中间语言(IL)的低级语言。在运行时,IL代码使

用一个JIT编译器把中间语言编译为本机代码。JIT编译器允许根据使用的操作系统和硬件

进行代码优化,因此在很大程序上抵消了编译的性能成本。

CLR托管代码的一个主要的好处是垃圾收集。在以前的编程语言中,是由开发人员负

责释放程序使用的所有资源,如果资源使用完后没有被释放,会造成许多细微的难以觉察的

bug»因为系统没有办法收回这些资源占用的内存,应用程序的性能就会逐渐降低。现在,

开发人员只需负责释放非托管的资源并尽快释放昂贵的资源,.NET垃圾收集器负责销毁无

用的托管对象,并释放它们占用的内存。

通用类型系统

.NET规范了方法调用的方式,并为所有的语言提供了相同的类型。我们甚至可以在一

种.NET语言中继承用另一种.NET语言编写的基类。这就意味着C#程序员和VB.net程序可

以合作开发同一个项目。

程序集

.NET代码被部署为一种称为程序集(assembly)的逻辑单元。程序集可以是一个类库

(DLL),一个控制台程序或Windows应用程序,--^Windows服务,甚至是,•个ASP.NET

页。程序集可以包括一个或多个物理文件。

程序集不需要特殊的安装过程——只把文件拷贝到目标机器在上就可以了。不存在一个

中央注册表,用来存放关于.NET所有组成部分的信息。因为程序不需要注册和根本一个惟

一的ProgID,在一台机器上可以安装一个组件的多个版本(并行版本化)。

COM互操作性

,NET的所有这些功能都可以让开发工作更加轻松,但还有一个潜在的问题一一因

为.NET几乎在每个方面都是全新的,无法很容易地把托管.NET代码和遗留的COM代码混

合在•起。微软的解决办法是提供工作为.NET程序集生成COM类型库,读取COM类型库

并用它们生成.NET包装器。

Framework类库

.NET最大的优点之一是它提供的数量庞大的类库。这些类库继承了大部分的Windows

API函数的功能,还提供了许多更高级别的操作,如:

Windows窗体

Web窗体

ADO.net

Remoting

数据访问、XML串行化和字符串与集合的处理等

VS.NET的安装

i.运行环境

CPU:PIII600以上

内存:128M以上

硬盘空间:2G

开发环境:WINDOWS2003/WINDOWSXP/WINDOWS2000+SP3

运行环境:任何WINDOWS操作系统

2.安装前的准备

删除系统中原有的所有测试版VisualS组件

删除VisualStudioAnalyzer6.0

安装IE6.0

安装,netFrameWork1.1

安装FRONTPAGE2000WEB客户端扩展

VS.net的设计界面

b)菜单/工具栏

C)窗体设计器

d)控件栏

e)属性栏

f)代码编辑器

C#语法

编译和程序结构

基本的C#语法

□冒号:指明继承/接口等

□分号:指明一条代码语的结束

□花括号:包括代码块/作用域分隔符/数组初始化

□方括号:数组声明/访问数组元素

□圆括号:调用承数/强制类型转换/定义表达式运算顺序

注释:

1.//-单行注释

2./**/—多行注释

3.///-XML文楼注释,这种类型的注释可由编译器处理,并放置在XML文件。

Ctel.bt

Main。函数

每个程序都需要一个入口点,即程序开始招待的地方。在C#中,入口点是Main方法。

每个C#应用程序至少定义一个Main方法。定义多个Main方法也是可以的,但在编译时必

须选择哪个Main方法作为入口点。

因为Main方法在创建任何类或结构的实例前被调用,因此它必须声明为static(静态)。

Main方法有几种可以接受的方法签名:

publicstaticvoidMain()

publicstaticintMain()

publicstaticvoidMain()string[]args)

publicstaticintMain(string[]args)

最后两种形式用来向Main()方法传递命令行参数——任何参数都被作为string类型的数

据传递。方法的返回值必须是void或int类型。后者反映了C语言中使用返回值表示程序

结束方式的约定。返回值为0表示程序正常退出,非0的返回值表明程序出现了错误。

命名空间

命名空间是C#、接口、委托、枚举和其他类型的一个逻辑上的组合。便如,需要使用

正则表达式时,可以在System.Text.RegularExpressions命令空间中查找和它相关的类型。命

名空间还用来防止类型之间的命名冲突。如果要在应用程序中使用一个库,而该库中定义的

一个类型和已经定义的一个类型同名,就会产生问题。但是,如果库中定义的类型包含在独

立的命名空间中,就不会有这样的问题了。

.NETFramework类库本身就被组织为--系列的命名空间。开发自己的C#代码时,可以

把代码放在一个自己的命名空间中——如果您没有定义自己的命名空间,代码会自动放入一

个没有名称的全局命名空间中。要创建命名空间,只需使用namespace关键字定义一个代码

块,如下例所示。

命名空间可以嵌套。它不必是连续的代码,这一点和类不同。命名空间的各个元素可以

放在不同的源文件中,一个源文件可以包含几个命名空间。一个命名空间中,每个类型定

义必须是惟一的,不能包括两个同名的类。可以随意命名命名空间,行业约定为:

□命名空间的名称中每个单词的第一个字母应该大写

□命名空间的名称的第一部分通常是一个公司或组织的名称

□命名空间名称的第二部分应该是相关技术的名称,后面跟可选的特性和设计名

NamespaceAnimals

namespaceBirds

publicclassSparrow

{

//CodelistingforSparrowclass

访问包含在命名空间中的•个类型的方法是使用该类型的全名,包括它所在的命名空间

的名称。使用类型的全名非常麻烦,C#提供了using关键字,它和Java中的import语句相

似。

C#类型系统

通用类型系统(CTS)是定义C#和.NETFramework中的•组预定义类型,以及所有类

型行为的一个规范。它定义一个声明、使用和管理类型的标准化框架,因而促进了用不同编

程语言编写的类型之间的集成。用各种语言写的类型必须遵循它定义的基本规则,以保证类

型安全和性能的优化。

不是所有的.NET语言都支持在CTS中定义的所有类型,因此任何类只要其成员中有不

受支持的类型,那么该类就可能无法从某些语言中访问。

CTS区分两种基本类型——值类型和引用类型。这两种类型之间的根本区别在于它们

在内存中存储的方式。.NET使用两种不同的物理内存来存储数据——栈和托管堆。

值类型总是在内存中占用一个预定义的字节数(例如,int类型占用4个字节,而stimg

类型占用的字节数会根据字符串的长度不同而不同),当声明一个值类型变量时,会在栈中

分配适当大小的内存(除了引用类型的值类型成员外,如类的int字段),内存中的这个空

间用来存储变量所含的值。

引用变量也利用栈,但这时栈包含的只是对另个内存位置的引用,而不是实际值。对

象的实际数据放在另一个内存堆中。为了在不使用在堆中的分配的内存时将它释放,.NET

定期执行垃圾收集,对引用不再有效的对象使用的内存进行回收。

值类型

值类型代表基本数据类型,如整型或浮点型。值类型分为三种:枚举、内建值类型、,

用户定义的值类型(结构)

内建值类型

结构名称C#别名说明联欢会范围

Booleanbool布尔值true或false

Bytebyte8位无符号整数0至1」255

Charchar16位Unicode字符

Decimaldecimal128位高精度

Doubledouble64位双精度浮点数

Int16short16位有符号整数-32768〜32767

Int32int32位有符号整数

Int64long64位有符号整数

Sbytesbyte8位有符号整数

Singlefloat32位单精度浮点数

UIntl6ushort16位无符号整数

UInt32unit32位无符号整数

UInt64ulong64位无符号整数

IntPtr大小取决于平台的有符号整数(32位系统/64位系统)

UintPtr取决于平台的无符号整数

TypedReferace指向内存中存储数据位置的指针,和存储在该位置的数据类型的

表示

平台特定的整数(IntPtr/UintPtr)用于本机资源,如窗口句柄等。资源大小取决于使用

的硬件和操作系统,但其大小部总是足以包含系统的指针。IntPtr与CLS兼容,而无符号整

数不娈容。

声明一个内建值类型的变量

C#是强类型化的语言——声明变量明必须指定其类型。有两种办法可以声明一个内建

值类型的变量。可以使用结构的全名或别名。

System.Int32width;

同于

Intwidth;

可以在声明一个值类型时将它初始化,方法是在变量声明语句中赋一个值:

intheight=4;

字面量值(常数)

整型字面量默认为可以存放值的最小类型,依次为int/unit/long/ulong

浮点型字面量默认为double

如果希望把字面量标记为默认类型以外的数据类型,可以在字面量后面加一后缀,显式

指定它的类型。

类型后缀

unitu

long1

ulongul

floatf

decimalm

例如:floatamount=23.7F;

char的转义字符

转义字符说明

\'单引号

\"双引号

\\反斜杠

\0空值

\a警告

\b退格

\f换页

\n换行

\r回车

\t制表符

\v垂宜制表符

引用类型

引用类型包含一个指针,指向堆中存储对象本身的位置。因为引用类型只包含引用,不

包含实际的值,对方法体内参数所做的任何修改都将影响传递给方法调用的引用类型的变

量。因此,在某些方面和引用参数相似。

引用类型包括指针、接口和自描述类型。自描述的引用类型包括类的类型和数组。数组

代表一组元素,这些元素可以是值类型或引用类型。即使元素是值类型,数组也中引用类型。

有两种引用类型在C#受到了特别重视:

第一种是Object类(别名:object)。这是所有值类型和引用类型的最终基类。因为所

有的.NET类型都派生自Object类,所以从Object继承是自然的,不必声明

另一种是String类。字符串代表一个固定不变的Unicode字符序列。这种不变性意味着,

一旦在堆中分配了一个字符串,它的值将永远不会改变。如果值改变了,.NET就创建一个

全新的String对象,并把它赋值给该变量。这意味着,字符串在很多文献都像值类型,而不

像引用类型。如果把一个字符串传递给方法,然后在方法体内改变参数的值,这不会影响最

初的字符串。C#提供了别名string来代表System.String类。

下面三个表达式都是创建string类型变量的正确方法:

stringstrA=newstring,A',5);

stringstrB="Zachary”;

stringstrC=@"Thislinecanwrap,andcancontainbackslashes(\),etc.^^;

两个字符串可以使用+运算符达到连接的H的。

提取string中给定位置上的字符可以使用索引器语法:

stringstr="ByeBye”;

charfirstChar=str[O];

确定类型

确定变量类型有两种方法。可以使用在Object类中定义的GetType。方法,返回一个Type

对象。另一种方法是使用typeof运算符做同样的事件。Typeof运算符的参数是类型的完全

限定名称,或者是类型的别名。

Obj.GetType()

Typeof(string)

强制类型转换

因为收缩转换会导致丢失数据,在转换前我们要检查实际值是否可以存放在int型变量

中。另一个办法是使用checked运算符,如果转换时丢失数据将抛出•个错误。

可以隐式转换的数据类型如下表:

原始类型转换为

bytedecimal,double,float,int,long,short,unit,ulong,ushort

chardecimal,double,float,int,long,unit,ulong,ushort

floatdouble

intdecimal,double,float,long

longdecimal,double,float

sbytedecimal,double,float,int,long,short

shortdecimal,double,float,int,long

unitdecimal,double,float,long,ulong

ulongdecimal,double,float

ushortdecimal,double,float,int,long,unit,ulong

装箱和拆箱

值类型和引用类型都是从Object类派生来的,这意味着任何•个值类型都可以调用一

个Object类方法:

值类型变量被隐式转换为引用类型时,称之为装箱,反之称为拆箱

intj=4;

stringstr=j.ToString();〃装箱

intk=(int)str;〃拆箱

运算符

算术运算符

运算符说明

+加法运算符

减法或负值

*乘法运算符

/除法运算符

按位求补运算

%求模运算

前置后置增量运算

—前置后置减量运算

赋值运算符

运算符说明

赋值运算符

+=a+=b等效于a=a+b

*=

/=

%=

关系运算符

运算符说明

等于

!=不等于

<小于

<=小于或等于

>大于

>=大于或等于

逻辑运算符

运算符说明

&按位与

1按位或

A按位异或

&&逻辑与

II逻辑或

1逻辑非

?:三元运算

对象运算符

运算符说明

(<type>)类型强制转换运算符

[]访问数组或集合的个元素,或者作为索引器运算符

typeof返回对象类型

sizeof检索结构的大小

句号成员访问

is对象比较,用来确定一个对象是否派生自另一个类

as执行对象向下转换,失败时返回空值

new调用构造函数。对于引用类型,在堆上分配一个新对象。对

于值类型,值类型的字段被初始化为默认值

间接寻址和地址运算符

运算符说明

*取地址所含值

&取值的地址

->访问结构指针成员

其他运算符

运算符说明

checked打开算术检查

unchecked关闭算术检查

程序流程和异常处理

条件语句

if-else语句:

if(条件二)

〃条件二成立时执行

elseif(条件二)

〃条件二成立时执行

}

else

//条件都不成立时执行

}

switch语句

给一个或几个条件语句求值,与包含在case子句中的一个或儿个常量表达示进行比较,

如果表达式匹配case子句,则执行后而后面的代码。若表达式不匹配任何case子句,defoult

关键字执行后面的代码块。

Switch(表达式)

{

case分支表达式一:

执行语句

break;

case分支表达式二:

执行语句

break;

case分支表达式三:

执行语句

break;

default:

默认语句

break;

表达式必须是一个预定义的整型类型或String。Case子句以•个冒号结束,代码不需要

包括在花括号中。可以把两个或多个case子句放在一起。分支内必须使用break语句跑出

switch语句。也可以goto语句转到另一个分支。

迭代循环

for语句

fbr(初值;条件表达式;增值表达式)

〃循环语句

}

foreach语句

fbreach(type_valueinlenumcrable)

//循环语句

}

while语句

while(条件)

{

〃循环体

dowhile语句

do

//循环体

}while(条件)

跳转语句

break语句

用来退出do-while、for>fbreach或while循环,还用于退出switch语句。

Continue语句

用来退出循环的肖前执行,返回循环顶部再次循环。

Goto语句

跳到另一行代码。后面跟一个标号名。标号将在程序的另外地方定义,它后面带一个冒

号。

不能跳到一个循环语句的中间,不能从一个类或一个finally块跳出。对于goto语句比

较合法的使用是,跳Hiswitch语句中的case了句。

Return语句

用来退出一个返回值为非void的方法。返回值为void的方法可以使用return语句,也

可以不使用。

异常处理

在C#中,异常处理的实现是通过使用try、catch、finally关键字定义代码块。

Try

{代码}

catch(异常类型)

{异常处理代码}

finally

{必执行的代码}

一个try代码块可以关联几个catch代码块,每个catch代码块捕捉不同的异常类型。

Finally代码块在程序控制离开try代码块时执行。用来执行必要的清除操作。

局部变量

局部变量是在方法内定义的变量。在类级声明的变量称为字段。

局部变量声明和赋值

每个变量在声明时必须定义变量的类型:<type><变量名〉;

访问修饰符如internal/private/protected/public/readonly/static关键字不能用于局部变

量,因为局部变量不能在定义它们的方法或代码块之外访问。

一个声明语句中,可以声明多个某种类型的变量:

intI,j,k;

所有的变量在使用前都必须赋值。可以在声明语句中赋值,也可以以后在代码中再赋值。

一个例外是使用out关键字给方法传递•个未初始化的变量。

通过使用new运算符调用类构造函数,或者提供数组元素的一个列有,也可以在声明

引用类型变量时对它们进行初始化。

局部变量的作用域

一个变量在特定的代码块中,能够被编译器识别,并能够被访问,这个代码块就是变量

的作用域。局部变量的作用域开始于声明它的那一点,虽然直到赋值才能访问它。一旦定义

变量的方法退HI,或包含变量的代码块执行完毕,该变量就离开了作用域。同一作用域中的

两个变量不能同名,但不同作用域中的变量可以有相同的名称。

由于子作用域完全嵌套在父作用域中,因此在子作用域中声明的变量不能和父作用域中

的局部变量同名。

数组

.NET定义了两个封装数组的类。Array类代表一个不可变的对象数组,一旦设置长度,

就不能改变它。另一个是ArrayList,它的长度可以即时调整。

创建一维数组

type[]arrayName;

arrayName=newtype[length];

或者:type[]arrayName=newtype[length];

创建多维数组

type[,]arrayName=newtypefnumRows,numCols];〃两维数组

创建更多维数组的方法是增中逗号的数量。

要创建一个行数固定,列数可变的二维锯齿形数,语法为:

type[][]arrayName=newtype[numrows][];

arrayName[O]=newtype[numColsO];

arrayName[1]=newtype[numCols1];

arrayName[2]=newtype[numCols2];

初始化数组

方法是声明数组时初始化它的元素:

string[]names={"Mark","Maria”,"Scott“,“Diana”};

或者:

string[]names=newstring口{“Mark","Maria”,"Scott“,“Diana"};

可以在多维数组中执行相似的初始化操作。每行的初始化值放在花括号中

string口names={{"Diana","Reid''},{"Ceryl”JSpada''},{"Scott","Palmer”}};

访问数组元素

要访问数组的元素,只需要把要访问的元素的下票放在数组名后面的方括号中。

C#数组的下标都是从0开始,如果使用了无效的下标,系统将抛聘个异常错误。

数组属性和方法

可以使用数组的GetLength()方法得出数组的长度。

Rank属笥返回数组的维数

Length属性反回数组元素的总数

Reverse方法反转数组元素的顺序。

Sort方法按照字母顺序或其他算法排列数组元素。

Clear方法把值类型的数组的一个或多个元素设为0,把引用类型元素设为空。

Indexof和lastindexof方法在数组中线性查找给定值的第一个具体值或最后一个具体值。

面向对象程序设计

类是C#中的两种基本封装构造之一(另一个是结构)。每个可执行的语句必须放在类或

结构中。类定义作为大多数C#程序的基本构件的引用类型。类是“面向对象编程”中的“对

象”的蓝图。

类是一种复合的引用类型,因为它可以包含数据成员、函数和嵌套类型。数据成员可以

包括常量和实例与静态变量字段。函数成员可以包括方法、属性、构造函数、析构函数、运

算符、索引器和事件。

C#有一个强大的功能,就是继承的概念。继承允许我们通过扩展现有基类的功能开发

一个新的派生类。派生类可以访问基类中定义的构造函数、方法、运算符等。这可以让我们

复用现有的代码并设置类的层次结构。.NETFramework中的每个类和自己编写的每个类的

层次结构都派生自Object类。Object类是C#中最终的基类。

定义类

可使用class关键字定义类。类的主体放在花括号中。我们前面说过,类的定义可以包

含任意数量的数据成员、函数和嵌套类型:

〈modifier〉class<class_name>

{

字段

方法

)

类修饰符

类的定义可以使用abstract、internal、new、private>protected>public或sealed关键字

进行修改。internal、private、protected和public关键字定义对类的访问。在命名空间中声明

的类只能有public或internal访问属性。嵌套类(在另一个类中定义的类)可以具有以上4

种访问类型中的一种,还可以有protectedinternal访问类型,它等效于“受保护的或内部的”

访问。不指定访问修改符,这时类的访问类型默认为internal。

修饰符说明

abstract不能创建该类的实例。这意味着该类的作用是作为基类。抽象类不能

密封

internal该类只能从同一个程序集的其他类中访问。这是非嵌套类型的默认访

问方式。如果没有指定修饰符,则类的访问方式为internal

new只用于嵌套的类。它指明类隐藏一个同名的被继承成员

private内部使用,可以用在嵌套类

protected只能从定义它的类中和自此派生的类中访问

public可以被任何其他类访问

sealed该类不能作为其他类的基类。换句话,该类不能被继承。类不能既是

密封的,又是抽象的

注意:Quad类的访问类型默认为internal。只能在同一程序集内部访问。

定义类示例

创建一个类实例

类的实例是一个引用类型的变量。因此,对象存放在堆中。创建类实例的语法中使用了

new关键字。

Class_namevariable_name=newclass_name(arguments);

New关键字的作用是调用••个称为构造函数的特殊函数。传递给构造函数的参数•般

用来初始化类实例的数据成员,虽然构造函数可以不带参数,并在以后进行所需字段的初始

化。

有些类可能没有可访问的构造函数,这种情况下就不能用构造函数来实例化该对象。这

些对象的实例•般是在.NETFramework的方法内部创建,这些方法返回对类实例的引用。

也可以用这种方法检索具有可访问构造函数的许多类的实例。例如,File类的Create。方法

(一个静态方法)返回对FileStream对象的引用。可以使用下面的语法对应•个名为data.inp

的文件实例化--个FileStream对象:

TypetypeTemp=testQ.GetType();

构造函数

构造函数是一个特殊的方法,一般用为初始化类实例的数据成员。构造函数名和类名总

是相同的。构造函数没有返回值。类可以定义任意数量的构造函数。运行时根据传递给构造

函数的输入参确定调用哪个构造函数。

构造函数访问修饰符常用public和protected,公有构造函数没有访问上的限制。它可以

在任何地方调用。访问类型为protected的构造函数只能被定义它的类型和定义它的类型所

派生的类型访问。

如果没有显式定义构造函数,系统将提供一个默认的、不带参数的public构造函数,它

将把数据成员初始化为默认值。如果希望拒绝对该构造函数的公有访问,可以用一个不同的

访问级别声明这个构造函数。

如果定义了一个无参数的private构造函数,我们将阻止该类被实例化(这种做法可以

针对这样的类:它只有静态成员,而又不能声明为abstract,因为我们想把它像System.Math

类一样声明为sealed)()

构造函数示例

调用基类构造函数

当创建类的实例时,它的创建工作包括它的基类的创建。从基类继承的任何数据成员必

须进行初始化。派生类的构造函数的一个操作是从它的直接基类中调用一个构造函数。这个

操作可以使用基类的默认(无参数)构造函数隐式地进行,也可以让派生类的构造函数显式

调用基类的构造函数。

如果基类没有定义无参数的构造函数,就必须显式地调用一个基类构造函数。调用基类

构造函数是使用冒号加base关键字。这个语法放在派生类的构造函数名的后面。基类构造

函数需要的任何参数以正常方式在圆括号中传递给构造函数。

调用基类构造函数示例

调用在同一样类中定义的构造函数

我们可以和调用基类构造函数相似的方式调用在同个类中定义的构造函数的另一种

重载形式。调用的方法是使用“:this”语法并给构造函数提供适当的输入参。这样做的的

•个原因是避免在构造函数之间重复编写代码。

静态构造函数

使用static关键字指定,通常用于初始化静态的数据成员。静态的数据成员与一个类型

相关,而不是与类型的一个实例相关。静态构造函数不允许有访问修饰符。不能显式地调用

静态构造函数,它在加载类是被运行时调用一次——在创建类的任何实例和引用类的任何静

态成员之前。静态的构造函数不被继承。静态构造函数从来不被显式调用,它只在运行时调

用。

示例:静态构造函数

析构函数和Finalize。方法

析构函数是在破坏一个对象时调用的方法。c#使用一个垃圾收集器来自动完成大部分

的类似工作。一般的准则是,除非有迫不得己的原因,不要使用析构函数,而应该把清除操

作交给运行时完成。

在c#中,定义析构函数的方法是把个代字号(~)放在类名的前面

如果使用析构函数,最重要的一点是注意我们能预计它什么时候调用——直到垃圾收集

器运行并把对象从内存中清除时,它才被执行。由于这个原因,如果在破坏类时,您有很昂

贵的非托管资源要释放,一般更倾向于使用Close。或Dispose。方法。当对象不再使用时,

程序员可以显式地调用这两个方法。事实上,析构函数都不能保证被调用,因为我们可以通

过调用System.GC类的SuppressFinalize。方法告诉垃圾收集器不要调用对象的析构函数。

处理托管和非托管资源

在C#的类型中有两种资源。一种是在.NET中定义的长管资源。另一种是类型可以访问

的非托管的外部资源。运行时可以在调用与类型相关的析构函数时处理非托管资源。但是,

也可以实现【disposable接口,允许我们的类的客户端显式要求释放资源。

【disposable接口声明一个方法Dispose。,它不带参数,返回类型为void。用来释放和对

象相关的托管和(或)非托管资源。实现【disposable接口的每个类都必须实现Dispose。方

法。

满足这两种处理需要的一个方法是再定义一个带一个bool参数的Dispose。方法。如果

参数为true,托管和非托管资源都进行处理。如果参数为flase,只处理非托管资源。第二个

Dispose。方法被无参数的Dispose。方法调用,并且是在该析构函数方法的内部调用。

示例:使用Dispose处理非托管资源

using语句

当using语句应用于对明时,using语句后面的代码块执行后马上处理对象占用的资源。

资源的处理是通过调用对象的Dispose。方法。不要把它和using关键字混淆,后者用来在不

使用完全限定的类型名的情况下访问命名空间的内容。

Using(object)

{

//codetoexecute

继承

继承是面向对象编程的支柱之一,是OOP鼓励代码复用的一种方式.继承可以通过托展

现有基类的功能来创建-,个新的派生类.继承也允许建立类的层次结构.公用功能可以放在基

类中,可以创建任意数量的派生类来利用此功能,而不用内部复制这些功能.

派生类继承自基类。在类的声明中,可以通过在基类名的后面加冒号来表示继承。

PublicclassEagle:Bird

C#只支持类的单一继承。类只能有一个直接的基类。虽然它的基类也能有一个基类。

派生类在访问基类时有定的限制。访问类型为private的基类成员不能被派生类访问。

访问类型为internal的基类成员只能被同一个程序集中的派生类(或任何类)访问。派

生类能够自由访问protectedprotectedinternal和public基类成员。

示例:类的继承

用户定义类型之间的强制转换

某些用户定义的类型之间也可以进行转换,如类、结构和接口。大多数转换要求在转换

的原类型或目标类型内定义强制转换,但许多转换允许隐式地进行,不用编写客飓的代码。

可以隐式转换的类型

原类型目标类型

任何类型object

任何派生类基类

任何类或结构被该类或结构实现的任何接口

null任何引用类型

另外,可以显式地把接口类型转换为实现该接口的类,可以把基类强制转换回子类,但

只有该对象属于那个具体类型才行。在其他情况下,需要在代码定义强制转换。

示例:派生类之间的强制转换

自定义的强制转换

用户定义的强制转换必须是public和static。我们还指定强制转换是隐式(implicit)的

还是显式(explicit)的(隐式的强制转换也可以显式地进行),目标类型,和源类型。

示例:自定义的强强制转换

不允许进行的强制转换

不能定义默认允许的强制转换(如把一个类强制转换为•个实现的接口),也不能定义

从基类到继承类的强制转,以下下表所列的转换:

原类型目标类型

任何类型相同类型

任何类型object

object任何类型

任何类型任何接口

任何接口任何类型

任何派生类基类

基类任何派生类

结构

结构是和类相似的一种封装构造,因为它可以包含数据、类型和函数成员。但和类不同

的是,结构是值类型,因此存放在内存中称为栈的地方。结构通常用来存放简单数据类型。

结构与类之间的差异

因为结构存放在栈中并按值传递,和存放在堆中的一个可比的类对象相比,它们具有性

能上的优势。原因之一,值类型的分配忆于引用类型。原因之二,存放在栈中的值一离开作

用域就立即被收回。不用等待垃圾惧器来完成工作。

但是,如果反结构作为参数传递给一个方法,这种做法会成为一个问题。当引用类型传

递给方法时,传递的只是对对象的引用。而对于结构,在传递前要复制它的一个完整的副本。

和引用类型相比,结构越复杂,复制造成的性能开销越大。因此,结构应该只用来表示小的

数据结构。

结构继承自System.VaiueType类,而System.ValueType类继承自object类。所以结构可

以调用object类的一些方法。

结构和类的另一个区别是,结构即不能定义无参数的构造函数,又不能定义析构函数。

无参数的构造函数是由运行时提供的,用来将所有的数据成员初始化为默认值,而结构定义

的构造函数必须为结构包含水量的每个字段赋值。

最后,和类不同的是,结构不支持实现继承,虽然它们可以提供•个或多个接口的实现。

结构隐式地从ValueType类和Object类继承,但它也隐式地是sealed类型,也就是说它不能

作为其他类型的基类。

定义结构

使用struct关键字定义结构。结构的主体部分是用花括号包围的一个代码块。

<access_modifier>struct<struct_name>

{

〃数据成员

//方法

因为不能继承,结构的成员不能声明为virtual。不能把结构定义为abstract0在结构的

定义中不必使用sealed关键字,因为它的类型默认为sealed。

示例:定义结构

创建结构实例

结构实例的创建和初始化也是分为两步。

struct_namevariable_name=newstruct_name(arguments);

参数被传递给构造函数并用来初始化备构的数据成员。如果没有给构造函数提供参数,

则调用默认的构造函数。

如果结构的数据成员为公有访问类型,可以通过直接访问数据成员对它们进行初始化。

接口

接口为类或结构提供了蓝图。它是一个能声明属性、索引器、事件和方法的编程构造。

它不为这些成员提供实现,只提供定义。实现接口的数据类型必须提供接口成员的实现,但

成员实现的方式要取决于类型的具体需要。

接口中声明的所有成员隐式地为public和abstract。虽然•个类只能继承,个基类,但

它可以实现任意数量的接口。结构也能实现接口。接口本身可以从多个基接口派生。

定义接口

<access>interface<name>

//interfacemembers

在命名空间中声明的接口可以被授予public或internal访问类型。嵌套的接口可以被授

予publicprotected^internalxprotectedinternal或private访问类型。默认的访问方式是internal»

接口成员(属性、索引器、事件或方法)隐式被声明为public和abstract访问类型。它

们声明时没有实现,没有访问修饰符。接口的名称约定是以一个大写的字母“I”开始。

publicinterfaceIShape

intNumSides{get;}//一个属性

doublegetAreaO;//•个方法

}

实现接口

类或结构要以通过在类型定义语句中包括冒号和接口名,来表明它正在实现接口。这和

表明继承的语法相同。一个类型能够实现多个接口。在这种情况下,接口名前后列出,中间

用逗号分隔。当一个类既继承一个基类又实现一个接口时,基类放在最前面。

PublicclassEagle:Bird,lanimal,Iraptor

一旦类型实现了接口,它必须为接口中声明的成员提供实现。基类或实现的接口从中派

生的任何基接口的成员也必须实现。类型能够按照它认为适当的任何方式实现要求的成员,

只要这种实现符合在接口中声明的成员语法。例如,可以把方法声明为virtual,但不能改变

该方法的参数列表或返回类型。

示例:接口的实现

接口的继承

接口可以扩展另一个接口。接口继承的语法和类继承的语法相同,派生的接口语法包括

冒号和基接口的名称。实现派生接口的类或结构也必须为在基接口中声明的成员提供实现。

接口支持多重继承表现在一个接口可以有多个基接口。

PublicinterfaceIcircle:Ishape,Idisposable

{

//Icircleinterfacemember

}

实现Icircle接口的类型必须实现在Icircle>Ishape和Idisposable接口中声明的成员。

接口映射

类型必须提供其基类列表中所有接口的实现。把成员实现和接口声明连接在起的过程

称为接口映射。

编译器从当前的类型开始,在类型层次结构中向上编译。如果一个类型的基类已经实现

了被继承的接口成员,则该类型就没有必要这样做了。

在某些情况下,通过比较能让事件变简单。如果在类型中定义的一个方法和在实现的接

口中声明的一个方法有相同的名称、返回类型和参数列表,则该方法被认为是一个适当的匹

配。属性、事件和索引器可以进行相似的一对一比较。

但在某些场合,情况会变得更复杂。例如,一个类实现了两个接口,这两个接口声明了

一个同名、同参数列表但不同返回类型的方法。不能在同一个类中定义这样的两个方法。只

能通过在成员名前加上该成员要关联的接口名称,便用一种称为接口成员显式实现的方法。

显式实现的接口没有返回类型,只能通过接口实例访问。

VoidIbank.Deposit(doubleb)

如果两个接口声明的一个成员具有完全相同的签名,可以把这两个接口成员都映射到•

个类或结构成员。

枚举

枚举是一个便利的值类型,它把名称映射为整型值.实际上,它创建一系列的别名.别名可

以让程序更容易理解。枚举另一个有用的特性是如果使用了没有在枚举中定义的值,编译器

将抛出一个错误。

定义一个枚举

<modifiers>enum<enum_name>:integer_type

(

namel=value1,

name2=value2,

nameN=valueN

}

声明为命令空间成员的枚举可以有public或internal访问属性。如果没有指定访问修饰

符,访问类型将默认为internal。嵌套的枚举可以有public、protected、internal、protected>

internal或private访问属性。

枚举可以用new关键字修饰,表明它隐藏一个被继承的成员。枚举不能被派生,所以

abstract和sealed修饰都不允许使用。您可以选择为枚举指定•个整型类型。有效的整型类

型是byte、short>int^long>ubyte^ushort、uint和ulong。默认的整型是32位整型,或int。

枚举定义的体包含枚举名和值的一个列表。值是可选的。如果不指定值,将使用默认值

0/1/2等。名称或值对用逗号分隔(不是分号)。列表中最后一个元素后面没有标点符号。枚

举成员隐式的访问类型为publico

PublicenuiriPlanet

{

Barth=1,

Mars=2,

Venus=3,

Jupiter=4

使用枚举

Planetp=Planet.Earth;

在条件语句中使用枚举元素时,不能把枚举元素直接和一个基本数据类型比较。如:

intj=2;if(j=Planet.Mars)

上面这段代码不会编译。必须首先把整数j转换为相主尖的枚举元素。一种办法是把这

个整型值强制转换为枚举的一个实例。

Jintj=2;iR(Planet)j=Planet.Mars)

Enum类的方法

System.Enum类为操作枚举提供了许多静态的方法。

方法说明

GetName()返回指定枚举类型中指定值所代表的名称

GetNames()返回指定枚举中所有的名称(string数组)

GetValues()返回枚举中包含的所有值(Array对象)

IsDefined()检测某个值是否在指定的枚举中定义

示例:枚举

字段

字段是一个在类或结构中定义中声明的变量,它可以被这个类或结构的所有成员函数使

用。字段可以是值类型或者是引用类型。大致有两种类型的字段:实例字段和静态字段。

实例字段

实例字段和类型的一个实例相关。类型的每个实例都有自己的字段副本,并且可以按它

认为适当的方式操作这个副本。

实例字段在定义它的类型内部总是可以访问的。让它在类型外部也能访问有三种方式。

第一种是使用访问修饰符把字段指定为internal>protected,protectedinternal或public。

字段默认的访问类型是privateo

第二种方式是使用方法,第三种方式是使用属性。

和字段关联的其他修饰符包括new、readonly和volatile关键字。New关键字指明该字

段隐藏了基类中定义的一个同名字段,readonly关键字防止字段在赋值后被修改,标记为

volatile的字段将限制编译器或运行时运载它进行的指令重排序优化操作,主要用于不同步

访问字段的多线程程序中。

示例:字段的定义

静态字段

静态字段是和类型本身相关的字段,而不是和类型的实例相关的字段。不论创建了多少

类型的实例,静态字段只有一个副本。静态字段无论什么时候使用总是可用的,而实例字段

只在创建了类型的一个实例时才能使用。

要定义静态字段,需要使用static关键字放在字段的声明语句中。静态字段的访问类型

经常设为public,以允许在定义它的类型的外部访问。可以使用类型的名称访问静态字段。

静态字段示例

访问修饰符

可以在字段声明语句中指定以下访问类型。如果没有指定,默认为private:

public:可以定义它的类的内部和外部自由访问

internal:只能被在同一个程序集中的定义的类型访问。

Protected:可以在定义它的类型中访问,在该类型的派生类型中也可以访问。

Protectedinternal:可以在同一个程序集中的类型和派生类中访问。

Private:只能在定义它的类中访问。

常量字段

使用const关键字放在字段声明语句中

<modifiers>const<type><fine_Name>=<value>;

常量字段在声明时必须赋值,并且该值在编译时必须是可计算的,常量字段隐式为静态

的,访问方式和访问静态字段相同。不能既把一个字段声明为const,又把它声明为static。

常量关键字只能用于一种内建的值类型,一个string或一个enum。除了字符串外,不

能把引用类型宝义为常量字段。

只读字段

只读字段和常量字段相似之处在于,一旦赋值就不能改变。然而,还有更多的赋值机会:

只读字段可以在声明它的地方赋值,或才在它所属类型的构造函数中赋值,但在别的地方就

不行了。只读字段默认为实例字段,意思是说,对于定义它的类型的每一个实例都有一个不

同的值。只读字段可是静态的,但必须显式地声明为静态的才行

要指定只读字段,把readonly关键字放在声明语句中:

<modifiers>readonly<type><field_name>;

如果不给只读字段赋值勤,它将使用默认值:值类型使用0,引用类型使用空值。下面

列出只读字段和常量字段的主要差别:

>常量字段总是静态的。只读字段可以是静态的,但默认不是。

>常量字段在声明时必须初始化,字段的值在编译是必须是可计算的。只读字段可以

是在声明时初始化或者在构造函数中声明,或者根本不声明。赋给只读字段的值可

以来自在运行时求值的变量。

A常量字段可以用作局部变量;只读字段不能。

>常量字段只能是内建的值类型、字符串或枚举值。而任何值类型或引用类型都可以

定义为只读字段。

Lock语句

Lock语句提供对引用类型变量的同步访问。任何引用类型的变量都可以被锁定。

Lock(variable)

{

//codetobeexecuted

)

lock语做的就是在指定变量上加一个互斥锁。互斥锁真到程序的执行离开加锁的代码块

时才解锁。一次只能有一个线程占用互斥锁并访问变量;其他想访问变量的线程处于休眠状

态,直到战友用锁的线程将锁释放。

示例:加锁

易变字段

在字段声明中包括volatile修饰符限制了对字段的优

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论