1、面向对象和组件C#编程科学出版社第二章第二章 程序结构、变量、类型、运算符程序结构、变量、类型、运算符李军武汉大学测绘学院“我成长”网站1/71第二章第二章 程序结构、变量、类型、运算符程序结构、变量、类型、运算符1234 程序结构程序结构变量、常量和字量变量、常量和字量类型类型运算符运算符5运算符优先级和结合性运算符优先级和结合性2/712.1 程序结构程序结构在1.7节,我们编写了一个Hello控制台程序,代码以下。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceH
2、elloAppclassProgramstaticvoidMain(stringargs)Console.WriteLine(Hello!);3/71最简单最简单Hello控制台程序代码控制台程序代码上面就是最简单Hello控制台程序代码吗?其实代码还可简化成下面形式:classProgramstaticvoidMain()System.Console.WriteLine(Hello!);它没有了前面四条using语句,也没有了namespace,Main()中也没有参数;但在Console前添加了“System.”。它才是最简单Hello控制台程序代码!4/712.1.1 用类比了解程序结构
3、用类比了解程序结构房屋好比是类class,房屋名称为HappyHouse;房屋入口是类中Main()函数。房主拥有那块土地称为myLand,它由namesapce定义:namespacemyLandclassHappyHousestaticvoidMain()System.Console.WriteLine(Hello!);5/71类比1)WriteLine可类比为其它土地(System)中房屋(Console)里面某个东西,用代码表示为:土地.房屋.东西;2)小数点“.”表示访问操作,比如myLand.HappyHouse.Main()表示:访问myLand中HappyHouseMain组员
4、。3)HappyHouse房主并没有定义WriteLine,但并不妨碍他借用他人东西。他在Main中就借用了基类库BCL函数:System.Console.WriteLine();6/712.1.2 命名空间命名空间用C#术语说,namespace关键字定义了命名空间,大括号中东西称为类型,语法以下:namespace空间名称定义类型大括号界定了范围。空间名称要唯一,不然无法界定命名空间中类型。类型中定义东西称为组员。以下所表示:namespace空间名称类型1组员类型2组员.7/71命名空间-一个分组符号namespace说明HelloApp是本项目标命名空间。命名空间就是一个程序集内相关类
5、型一个分组符号。System 内建数据、数学计算、垃圾搜集器 System.Drawing 处理图形和绘图,包含打印 System.Data 处理数据存取和管理,ADO.NET System.IO 管理对文件和流同时和异步访问System.Windows 处理基于窗体窗口创建System.Reflection 包含从程序集读取元数据类System.Threading 包含用于多线程编程类System.Collections 包含定义各种对象集接口和类8/71程序集、命名空间、类型和组员一个程序集能够包含任意个命名空间,每个命名空间又能够包含各种类型。用“对象浏览器”可见:程序集只有一个Hell
6、oApp命名空间,命名空间中类型是Program类(class),Object是Program基类;右边是Object类组员。9/71分析下面代码namespaceHelloApp/命名空间inta;/定义变量:错误!staticvoidMain()/定义函数:错误!classProgram10/712.1.3 引用引用using“引用”反应了C#编程组件思想:尽可能使用基类库或其它成熟程序集。usingSystem;说明了HelloApp项目引用(using)了System命名空间。System命名空间中,提供了大量关键类型,如System.Int32、string等类型,定义在内部程序集内
7、部程序集中中。using简化了对特定命名空间中类型引用方法引用方法。因为引用了System,所以编译器能够将Console类解析为这个命名空间组员。假如没有引用System,将出现一个编译器错误。也能够使用完全限定名来使用Console类函数:System.Console.WriteLine(Hello!);11/71系统自动添加引用-内部程序集内部程序集许多关键.NET命名空间包含在mscorlib.dll文件中。多数.NETFramework程序集都位于全局程序集缓存GAC特定目录下(默认下C:WindowsAssembly)。在创建本项目时,系统自动添加了一些全局程序集引用,对它们引用,
8、仅仅经过using关键字来指定命名空间即可。12/71引用外部程序集(doit)不在上图中列出程序集,都是外部程序集。对外部程序集,除了经过using关键字来指定命名空间,还需要告诉C#编译器包含引用类型程序集名字。比如,System.Drawing.Bitmap类型包含在另一个名为System.Drawing.dll程序集中。引用它方法以下:右键点击【引用】【添加引用】,然后在对话框中选择System.Drawing组件;见下列图。13/71添加System.Drawing.dll程序集14/71在Program.cs代码前添加:usingSystem.Drawing;你就能够在项目中添加图
9、形类型详细引用了,比如在Main()中加上语句:BitmapMap=newBitmap(20,20);Bitmap是System.Drawing命名空间中一个类。Map是Bitmap类型变量,经过Map=newBitmap(20,20);语句被赋值为Bitmap对象;即调用Bitmap类结构函数Bitmap(20,20)来创建一个对象。也可说Map是用new实例化一个Bitmap对象。注:命名空间与程序集普通是对应,命名空间为*,它程序集名字就为*.dll。15/712.1.4 格式化输出格式化输出在Main()中添加语句:Console.WriteLine(0,1,Hello,World!)
10、;系统输出:“Hello,World!”字符串。0、1标识嵌入在字符串中,它是格式化输出方法,与C语言printf()相同。能够使用这种花括号在文本内部指定占位符。在运行时,值会传入到WriteLine()来替换每一个占位符。16/71数据位置索引能够在字符串文本任意位置放置占位符,而不需要按照递增次序。比如代码:Console.WriteLine(1+0+2=3,10,20,30,60);/数据位置索引0123/输出:20+10+30=60后面数据10,20,30,60位置索引总是依递增次序0,1,2,3;而占位符n中n只能是03,0表明在占位符0上接收是索引为0数据(即10),1上接收是索
11、引为1数据(即20);而0排在1后面,故10在20后面显示。17/71格式化数值数据格式化数值数据假如数值数据需要更精细格式化,每一个占位符都能够(可选)包含不一样格式字符,下表显示了关键格式化选项。18/71使用一些格式化标识(doit)给定占位符值以冒号为标识,将这些字符作为后缀(比如,0:C、1:d、2:X)。修改Main()方法,添加下面语句,从而格式化一个固定值。比如:/使用一些格式化标识Console.WriteLine(Thevalue88888invariousformats:);Console.WriteLine(cformat:0:c,88888);/0代表占位符Conso
12、le.WriteLine(d9format:0:d9,88888);/补零到9位,前补零Console.WriteLine(f3format:0:f3,88888);/f3保留小数点后3位Console.WriteLine(nformat:0:n,88888);/注意,十六进制数大小写形式决定了字母是大写还是小写。Console.WriteLine(Eformat:0:E,88888);Console.WriteLine(eformat:0:e,88888);Console.WriteLine(Xformat:0:X,88888);Console.WriteLine(xformat:0:x,8
13、8888);19/71应用程序输出(doit)20/71 在控制台应用程序外格式化数值数据在控制台应用程序外格式化数值数据.NET字符串格式化字符不局限于在控制台程序中使用!一样格式化语法能够在调用静态string.Format()方法时使用。假如我们需要对任何应用程序类型(桌面GUI程序、Web程序等)在运行时组合文本数据,这个方法就很有用。在消息对话框中显示:/使用string.Format()来格式化字符串文本stringuserSt=string.Format(100inhexis0:x,100);/需要引用System.Windows.Forms.dll才能编译这行代码System.
14、Windows.Forms.MessageBox.Show(userSt);注意string.Format()是按照提供标志进行格式化。至此,我们就能够任意使用需要文本数据了。21/712.2 变量、常量和字量变量、常量和字量2.2.1 变量申明变量申明定义或申明变量方法以下:类型var_name;类型var_name=初值;其中var_name是变量名称(标识符)。注:假如是在类中定义变量,申明时可加修饰符(细节见后面章节)22/712.2.3 变量种类和赋值变量种类和赋值2.2.2 变量命名变量命名(自学自学)变量分为八种类别:变量分为八种类别:静态、非静态变量、数组元素、局部变量静态、非
15、静态变量、数组元素、局部变量,值参数、引用参数、输出参数、数组参数。值参数、引用参数、输出参数、数组参数。注意:在C#中,不能定义全局变量。【例【例2-3】变量种类。】变量种类。classProgram/类intx=1;/x是非静态变量publicstaticinty=2;/y是静态变量voidf(ints,intval,refinti,outintj)/数组s,值参数valintw=2;/w是局部变量j=x+y+i+w;/j是输出参数x是非静态变量,是非静态变量,y是静态变量,是静态变量,s是数组,是数组,val是值参数,是值参数,i是引用参数,是引用参数,j是输出参数。是输出参数。23/7
16、12.2.4 常量和字量常量和字量常量申明语法为:修饰符const类型ConstName;在申明常量时,要用到const关键字。下面是一个申明常量例子:publicconstdoublePI=3.1415926;字量字量字量就是类型字面值。它与常量本质上相同,但它愈加简单:不用申明,把值直接写出来即可。比如,下面语句中出现123就是整数字量:inti=123;24/71字符串字量字符串字量strings3=“HellonWorld!”;/串包含转义序列n,换行Console.WriteLine(0,s3);运行结果:Hello World!逐字字符串字量逐字字符串字量逐字字符串字量由字符和后面
17、双引号中多个字符组成,假如包含转义序列或Unicode字符,都作为普通字符处理。即“转义”失效。比如:strings1=HelloWorld!;/有字符串strings2=HellonWorld!;/串包含转义序列n,但作为二个普通字符处理,即:和nConsole.WriteLine(01,s1,s2);运行结果:HelloWorld!HellonWorld!25/71空字量空字量空字量只有一个:null。null本质含义是没有任何值,即“空”。null不属于任何类型,但它可隐式地转换为任何可接收空值类型,如引用类型。字符串和object都是引用类型,所以下面语句是正确:stringst=nu
18、ll;/null不等价于无字符串objectobj=null;/表示obj没有任何值26/71可空类型int?但下面语句不正确:inti=null;简单类型不是可空类型,所以int类型变量不接收null所以C#提供了“可空类型”这种语法,只要在任何“不可空”类型后加?就组成了可空类型,如“int?”,所以下面语句是正确:int?i=null;float?f=null;27/712.3 类型类型计算机科学家Wirth提出过一个公式:算法+数据结构=程序数据结构在.NET中形式就是公共类型系统,简称类型(Type)。一个变量用于连接一个名称(变量名)和一小块内存。一个变量有它值,也就是这小块内存中
19、存放值。至于这小块内存大小,以及怎样解释其中存放数据,是和变量类型相关。28/71整个C#类型系统29/712.3.1 类型分类类型分类1)值类型和引用类型(分类方法)值类型和引用类型(分类方法1)假如按变量存放是数据还是数据引用来区分,C#类型(或CTS)可分为值类型和引用类型,见下列图。30/71深入划分深入划分值类型深入划分值类型深入划分:简单类型(simpletype)枚举类型(enumtype)结构类型(structtype)引用类型深入划分:引用类型深入划分:类类型(classtype)接口类型(interfacetype)数组类型(arraytype)委托类型(delegatet
20、ype)字符串类型(stringtype)31/71代码例子代码例子值类型变量直接包含它们数据,而引用类型变量存放是它们数据引用(即对象引用)。比如:inti=1;/i是值类型变量,1直接存放在i中。objectobj=newobject();obj是引用类型变量,obj存放是对象引用。32/71怎样了解引用类型怎样了解引用类型“引用类型到底是什么东西啊?”我们用比喻法往返答您问题。计算机内存是用于存放数据,所以内存好比是房屋。只有二种房屋:一个是“堆”,另一个是“栈”。但每种房屋会有许多房间,用“房间号”区分它们,“房间号”其实就是内存地址。doublex=12.3;/x是值类型变量,12.
21、3直接存放在x中。doubley=x;/y是值类型变量,y=x造成12.3存放在y中。strings1=newstring(w,3);/s1是引用类型变量,s1存放是地址0 x01-对象引用。strings2=Hello;/s2存放是地址0 x02对象Hello引用。strings3;/s3是引用类型变量,s3什么也没有存放。strings4=s2;/s4=s2,造成地址0 x02存放在s4中。33/71内建系统类型和自定义类型内建系统类型和自定义类型(分类方法(分类方法2)假如按类型是系统定义好还是用户自定义来区分,C#类型可分为内建系统类型和自定义类型。有5种C#类型可由用户自定义:类类型
22、、结构类型、接口类型、枚举类型和委托类型。其它都是系统内建好,用户可直接使用。内建系统类型=简单类型+两个引用类型(string和object类)34/71C#内建系统类型35/71CLS类型注:符合CLS类型能够被任何托管编程语言使用。假如你程序中出现了不符合CLS数据,那么其它语言可能就不能使用它们。上表中,有一列(系统类型)专门给出了每种类型完整名称。C#全部基本类型都有一个短名称和一个完整名称。完整名称对应于BCL中命名类型。这个名称在全部语言中都是相同。其实从编译器角度看,两种名称是完全一样,最终都将生成一样代码。36/71自定义值类型(枚举和结构)自定义值类型(枚举和结构)其它其它
23、“自定义类型自定义类型”见第见第3章之后内容章之后内容1)枚举枚举枚举类型是一组命名常数值类型。下面Color枚举类型有三个命名常数:Red、Green和Blue;它们值分别为0、1和2。enumColorRed,Green,Blue即使数值0、1、2代表三种颜色,但用命名(Red、Green、Blue)显然要好些,名称更加好记忆与了解。这正是我们用枚举原因所在。37/71下面程序演示了枚举使用方法classProgramenumColor/定义枚举Red,Green,BluestaticvoidMain(stringargs)Colormyc=Color.Green;/给枚举变量赋值swit
24、ch(myc)/判断枚举变量是什么值caseColor.Red:Console.WriteLine(redvalue=0,(int)myc);break;caseColor.Green:Console.WriteLine(greenvalue=0,(int)myc);break;caseColor.Blue:Console.WriteLine(bluevalue=0,(int)myc);break;38/712)结构)结构像类一样,结构能够包含数据组员和函数组员;与类不一样是:结构是值类型(不用分配堆),结构类型变量直接保留结构数据,而不是对象引用。结构普通定义为:修饰符struct结构名/下
25、面是结构体,用于定义结构组员修饰符类型字段;/数据组员修饰符类型方法()/方法39/71结构存在原因普通情况下,用类即可满足要求;但假如要求程序性能高(运行快,节约空间),对于小数据结构,用结构能够节约存放空间。这正是结构存在原因所在。下面定义了点结构:structPointpublicintx,y;publicPoint(intx,inty)this.x=x;this.y=y;40/71使用结构代码片段以下:Pointp1=newPoint(10,10);/给结构变量赋值Pointp2=p1;/赋值使p2建立了一个p1副本p1.x=100;/修改p1.x,但p2.x不会受影响假如用类定义Po
26、int,则p2=p1语句使p1和p2变量引用同一个对象,当修改p1值(p1.x=100),p2.x也发生了改变。这正是值类型与引用类型差异。41/71可空类型和不可空类型可空类型和不可空类型(分类方法(分类方法3)假如按类型是否接收null值来区分,C#类型可分为可空类型(可空类型(Nullable)和不可空类型。)和不可空类型。引用类型是可空类型,而其它是不可空类型。但C#提供了一个“可空类型”语法,只要在任何不可空类型后加“?”,就组成了可空类型,如“int?”、“bool?”,所以下面语句是正确:int?i=null;/null不等价于0stringst=null;/null不等价于无字
27、符串42/71泛型和非泛型(分类方法泛型和非泛型(分类方法4)泛型泛型 见第见第12章章假如按类型是否接收参数来区分,C#类型可分为泛型(generic)和非泛型。泛型引入了类型参数,由一个泛型能够派生出许多特定类型。“可空类型”语法其实就是泛型System.Nullable简写,其中T是参数。int?是System.Nullable简写。下面二条语句是等价:int?i=null;System.Nullablej=null;43/712.3.2 简单类型简单类型(系统定义值类型)(系统定义值类型)简单类型包含数值类型以及bool和char类型。内容见教材,请自学2.3.4 结构类型(自定义值类
28、型)结构类型(自定义值类型)内容见教材,请自学44/712.3.5 字符串字符串(系统定义引用类型)(系统定义引用类型)【例2-10】字符串操作:“加”法,取子字符串,替换,插入等。staticvoidMain()strings1=小鸟;/定义一个字符串变量s1,并赋值strings2=s1+翱翔;/字符串“加”法/结果:s2=小鸟翱翔strings3=s2.Substring(1,3);/从字符串开始位置1,取得长度为3子串/结果:s3=鸟翱翔s3=s2.Replace(翱翔,自由);/把s2中子串翱翔替换为自由/结果:s3=小鸟自由s3=s3.Insert(2,-);/从位置2,插入字符串
29、-/结果:s3=小鸟-自由boolisEqual=(s1=s2);/判断二个字符串是否相等/结果:isEqual=falseboolisContain=s2.Contains(鸟翱翔);/判断s2中是否包含某字符串/结果:isContain=true/静态方法Format,格式化一个字符串,它与控制台程序格式化是相同。s1=string.Format(小鸟飞了0公里,9);/结果:s1=小鸟飞了9公里45/71部分string方法和属性46/712.3.6 数组(自定义引用类型)数组(自定义引用类型)数组是一个含有相同类型和名称变量集合,如一组整数、一组字符等。1)一维数组一维数组一维数组类型
30、语法是在“非数组类型”后放方括号,普通形式为:非数组类型inta;/申明了一个数组变量a,初值null,a还没有分配内存空间。a=newint2;/在堆上分配了有2个整数单元内存,其地址赋给了变量aa0=6;a1=4;/对数组元素进行赋值。47/712)多维数组(矩形数组)多维数组(矩形数组)普通形式为:非数组类型n个逗号n个逗号表示是数组维度,即n+1维数组。比如,int,表示二维整数数组类型,而下面语句申明了一个二维数组b:int,b=newint3,21,2,3,4,5,6;或:int,b=newint3,21,2,3,4,5,6;48/712.3.7 object类型类型(系统定义引用
31、类型)(系统定义引用类型)全部结构类型隐式地继承object类型,这么任何类型值都能够被处理成对象。值类型值能够经过执行装箱(boxing)操作处理为对象,也可用取消装箱unboxing,把object对象还原成值类型值。inti=123;objectobj=(object)i;/装箱intj=(int)obj;/取消装箱49/712.3.8 变量类型之间转换变量类型之间转换有四种转换方式:隐式转换、强制类型转换、ToString函数、Convert类。1)隐式转换)隐式转换若两种变量类型是兼容或者目标类型取值范围大于源类型时就能够使用隐式转换。inti=12;doublef=i;/隐式转换成
32、功i=f;/不成功,因为f取值范围大于i50/712)强制类型转换强制类型转换强制类型转换告诉编译器:将一个类型变量转换为另外一个类型变量。隐式转换不能满足全部编程需要,很多时候还是需要强制类型转换。但强制转换可能产生结果不够准确。强制类型转换语法为:(target-type)变量或表示式;inti=2;doubled=3.4;intv1=(int)(i+d);/强制转换:double-int数值51/713)ToString函数函数ToString函数用于将变量转化为字符串,各种类型变量都能够用ToString。下面代码把int变量转为字符串:inti=250;/i是整型变量strings=
33、i.ToString();/结果:变量s值是字符串“250”52/714)Convert类类ToString无法把一个字符串转为double类型值。但可使用Convert类进行显示转换。比如:doubler=Convert.ToDouble(“3.14”);/Convert是静态类,ToDouble是它函数运行结果:r=3.14,其值是由字符串“3.14”显示转换来。表2-9Convert类常见函数(见教材)53/712.4 运算符运算符运算符是用来定义表示式操作符。C#提供了大量运算符,从功效上可分为:算术运算符(+,-,*,/,%)位运算符(,&,|,)逻辑运算符(&,|,!)条件(赋值)
34、运算符(?:)赋值运算符(=,+=,-=,*=,/=,%=,位运算符=)关系运算符(=,!=,=)从运算对象上能够分为:单目运算符、双目运算符和三目运算符。54/712.4.1 算术运算符和自增自减运算符算术运算符和自增自减运算符算术运算符是指对数值(如整数、小数等)进行算术运算所用运算符,包含:加(+)、减(-)、乘(*)、除(/)、取余(%)自增和自减运算符包含:+,-自增运算符其实是加1简化表示法,自减运算符是减1简化表示法。比如x=x+1,用自增表示式表示为:x+,或:+x55/712.4.2 位运算符位运算符位运算符有六种:,&,|,5&y=5);/y=5为true,但x5为fals
35、e,故a=false结果:a=false其它逻辑运算见教材。58/712.4.4 关系运算符关系运算符关系运算符又称为比较运算符,包含:=,!=,=它们普通用于条件表示式中,用来判断表示式是否符合条件。以上运算符含义见教材表2-13。假设x和y是double变量,如x=-6.4,y=3,则下面都是正当关系表示式:xyx+3=y(x3)!=(y=5)三个关系表示式结果分别为:false,false,true59/712.4.5 条件运算符条件运算符条件运算符是C#中唯一一个三元运算符。普通形式为:?:假如满足条件就执行表示式1,不然执行表示式2。条件运算符常惯用于条件赋值,普通形式为:变量=?:
36、intb,x=6,y=4;b=(y一元算术移位关系按位逻辑赋值表示优先级高于。运算符中一元运算符(!等)是例外,其它都遵照这个规律。67/712.5.2 运算符结合性运算符结合性结合性表示:当优先级相同时候,按照运算符结合方向确定运算次序。运算符结合性分为两种方式:左结合(从左到右)右结合(从右向左)左结合-从左到右,是普通方式。比如算术运算符:+,-,*,/68/71结合性结合性只有三个运算符是从右至左结合,它们是:一元运算符、条件运算符、赋值运算符。其它都是从左至右结合。从左至右结合:x=10/2*5;/等价于x=(10/2)*5;赋值运算符从右至左结合:x=y=3;/等价于y=3;x=y;点运算是自左向右结合,所以a.b.c含义是(a.b).c而不是a.(b.c)。System.Console.Write(OK);/等价于:(System.Console).Write(OK);69/712.6 编程练习编程练习1 编程要求编程要求编写一个控制台程序,程序能够从键盘读一组正整数,读到-1结束;程序对输入一组正整数进行计数,并统计最大和最小数,最终输出它们。2 编程关键点编程关键点编程要用循环语句(while)等候用户从键盘输入,用条件语句(if)判断不一样情况,做不一样处理,然后用控制台WriteLine函数输出结果。70/71感激!71/71