C#第1章.docx
- 文档编号:8979358
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:59
- 大小:42.92KB
C#第1章.docx
《C#第1章.docx》由会员分享,可在线阅读,更多相关《C#第1章.docx(59页珍藏版)》请在冰点文库上搜索。
C#第1章
1.介绍
C#(读作“Csharp”)是一种简单、现代、面向对象且类型安全的编程语言。
C和C++程序员能很快熟悉它。
C#同时具备“应用程序快速开发”(RAD)语言的高效率和C++固有的强大能力。
VisualC#.NET是Microsoft的C#开发工具。
它包括交互式开发环境、可视化设计器(用于生成Windows和Web应用程序)、编译器和调试器。
VisualC#.NET是VisualStudio.NET的产品套件的组成部分,该产品套件还包括VisualBasic.NET、VisualC++.NET和JScript脚本语言。
所有这些语言都支持对Microsoft.NETFramework的访问,该框架包括一个公共执行引擎和一个丰富的类库。
.NETFramework定义了一个“公共语言规范”(CLS),这是一种通用规范,它确保遵循该规范的语言与类库之间实现无缝的互操作性。
对C#开发人员而言,这意味着即使C#是一种新语言,但仍可恰如其他成熟工具(如VisualBasic.NET和VisualC++.NET)一样,使用相同的、功能丰富的类库。
C#本身不包含类库。
本章的其余部分描述该语言的基本功能。
虽然后面的章节会详尽地(有时甚至以数学方式)对规则和例外情况进行描述,但本章的描述力求简洁明了,即便因此而影响完整性。
这样做是为了向读者提供关于该语言的概况,以方便读者编写早期的程序和阅读后面的章节。
1.1开始
经典性“hello,world”程序可以写为:
usingSystem;
classHello
{
staticvoidMain(){
Console.WriteLine("hello,world");
}
}
C#程序的源代码通常存储在一个或多个以.cs为文件扩展名的文本文件(如hello.cs)中。
可以通过VisualStudio.NET所提供的命令行编译器,使用以下命令行指令来编译此程序:
cschello.cs
它产生一个名为hello.exe的应用程序。
当此应用程序运行时,它产生的输出是:
hello,world
仔细观察此程序可以发现:
1)“usingSystem;”指令引用一个名为System的命名空间,它由Microsoft.NETFramework类库定义。
此命名空间包含Main方法中引用的Console类。
命名空间提供了一种分层方法来组织一个或多个程序中的各种元素。
用“using”指令指定一个命名空间后,该命名空间中的所有成员均可直接被引用。
所以,在“hello,world”程序中,可直接使用Console.WriteLine(而不必使用System.Console.WriteLine)。
2)Main方法是Hello类的成员。
它具有static修饰符,因此Main方法是相对于类Hello本身而不是相对于此类的实例。
3)应用程序的入口点(即当程序开始运行时首先被调用的方法)总是名为Main的静态方法。
4)“hello,world”输出依靠类库实现。
C#语言本身不提供类库,它使用公共的类库(VisualBasic.NET和VisualC++.NET也使用它)。
5)对C和C++开发人员而言,值得注意的是一些“没有”出现在“hello,world”程序中的东西。
6)该程序中的Main方法不是全局的。
C#不支持全局级别的方法和变量;这类元素总是包含在类型声明(如类声明和结构声明)中。
7)该程序没有使用“:
:
”运算符和“->”运算符。
在C#中,“:
:
”根本不是运算符,而“->”运算符仅在一小部分程序中使用,即那些涉及不安全代码的程序(第A节)。
分隔符“.”在复合名称中使用,如Console.WriteLine。
8)该程序没有包含前向声明。
C#中声明出现的顺序并不重要,所以不需要作前向声明。
9)该程序没有使用#include导入程序文本。
程序间的依赖项通过符号而不是文本来控制。
这样就消除了由多种语言编写的应用程序之间的障碍。
例如,Console类不需要用C#编写。
1.2类型
C#支持两种类型:
“值类型”和“引用类型”。
值类型包括简单类型(如char、int和float)、枚举类型和结构类型。
引用类型包括类(Class)类型、接口类型、委托类型和数组类型。
值类型与引用类型的区别在于值类型的变量直接包含其数据,而引用类型的变量则存储对象引用。
对于引用类型,两个变量可能引用同一对象,因此对一个变量的操作可能影响另一个变量所引用的对象。
对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响另一个变量。
示例
usingSystem;
classClass1
{
publicintValue=0;
}
classTest
{
staticvoidMain(){
intval1=0;
intval2=val1;
val2=123;
Class1ref1=newClass1();
Class1ref2=ref1;
ref2.Value=123;
Console.WriteLine("Values:
{0},{1}",val1,val2);
Console.WriteLine("Refs:
{0},{1}",ref1.Value,ref2.Value);
}
}
显示了这种区别。
运行该程序,可见下列输出:
Values:
0,123
Refs:
123,123
给局部变量val1赋值不会影响局部变量val2,这是因为两个局部变量都是值类型(int类型),每个局部变量都保存着各自的数据。
相反,赋值ref2.Value=123;则会影响到ref2,因为ref1和ref2所引用的其实是同一个对象。
应对代码行
Console.WriteLine("Values:
{0},{1}",val1,val2);
Console.WriteLine("Refs:
{0},{1}",ref1.Value,ref2.Value);
做进一步解释,因为方法Console.WriteLine的某些字符串格式化行为较复杂,它所需的参数数目是可变的。
第一个参数是字符串,它可能包含类似{0}和{1}这样编了号的占位符。
每个占位符都引用一个尾随参数:
{0}引用第二个参数,{1}引用第三个参数,依此类推。
在将输出发送到控制台之前,每个占位符都会被替换成它所引用的参数的值,并按规定的格式显示。
开发人员可以通过枚举声明和结构声明定义新的值类型,并可通过类声明、接口声明和委托声明定义新的引用类型。
示例
usingSystem;
publicenumColor
{
Red,Blue,Green
}
publicstructPoint
{
publicintx,y;
}
publicinterfaceIBase
{
voidF();
}
publicinterfaceIDerived:
IBase
{
voidG();
}
publicclassA
{
protectedvirtualvoidH(){
Console.WriteLine("A.H");
}
}
publicclassB:
A,IDerived
{
publicvoidF(){
Console.WriteLine("B.F,implementationofIDerived.F");
}
publicvoidG(){
Console.WriteLine("B.G,implementationofIDerived.G");
}
overrideprotectedvoidH(){
Console.WriteLine("B.H,overrideofA.H");
}
}
publicdelegatevoidEmptyDelegate();
列举了每种类型声明的示例。
后面几节将阐明关于类型声明的细节。
1.2.1预定义类型
C#提供了一组预定义的类型,这些类型中的大多数是C和C++开发人员所熟悉的。
预定义的类型中,属于引用类型的有object和string两类。
object类型是所有其他类型的最终基类型。
string类型用于表示Unicode字符串值。
string类型的值是不可变的。
预定义的值类型包括有符号整型、无符号整型、浮点型以及bool、char和decimal等类型。
属有符号整型的有sbyte、short、int和long;属无符号整型的有byte、ushort、uint和ulong;属浮点型的有float和double。
bool类型用于表示布尔值,即仅有真、假两个值。
设置bool类型可使编写的代码较易于实现自我文档化,并且有助于消除很常见的C++编码错误,即开发人员在本应使用“==”的地方错误地使用了“=”。
以下列代码为例:
inti=...;
F(i);
if(i=0)//Bug:
thetestshouldbe(i==0)
G();
如果在C#中编译这段代码,则会导致编译错误。
这是因为表达式i=0是int类型,而if语句要求bool类型的表达式。
char类型用于表示Unicode字符。
char类型的变量表示单个16位Unicode字符。
decimal类型适合于那些无法接受由浮点表示形式导致的舍入错误的计算。
常见的示例包括税务计算和货币转换这样的金融计算。
decimal类型提供28位有效数字。
下表列出了预定义类型,并说明如何为每种类型编写文本值。
类型
说明
示例
object
所有其他类型的最终基类型
objecto=null;
string
字符串类型;字符串是Unicode字符序列
strings="hello";
sbyte
8位有符号整型
sbyteval=12;
short
16位有符号整型
shortval=12;
int
32位有符号整型
intval=12;
long
64位有符号整型
longval1=12;
longval2=34L;
byte
8位无符号整型
byteval1=12;
ushort
16位无符号整型
ushortval1=12;
uint
32位无符号整型
uintval1=12;
uintval2=34U;
ulong
64位无符号整型
ulongval1=12;
ulongval2=34U;
ulongval3=56L;
ulongval4=78UL;
float
单精度浮点型
floatval=1.23F;
double
双精度浮点型
doubleval1=1.23;
doubleval2=4.56D;
bool
布尔型;bool值或为真或为假
boolval1=true;
boolval2=false;
char
字符类型;char值是一个Unicode字符
charval='h';
decimal
精确的小数类型,具有28个有效数字
decimalval=1.23M;
每个预定义类型都是一个在System命名空间内定义的类型的简写形式。
例如,关键字int所指的实际上是结构类型System.Int32。
就编写源代码的样式而言,使用关键字比使用完整的系统类型名称要好。
预定义的值类型(如int)在少数情况下会进行特殊处理,而大部分情况下完全像其他结构一样处理。
运算符重载使开发人员能够定义行为与预定义的值类型基本相同的新结构类型。
例如,Digit结构可支持与预定义整型相同的数学运算,并可定义Digit与预定义类型之间的转换。
预定义类型本身使用运算符重载。
例如,比较运算符==和!
=对于不同的预定义类型有不同的语义:
∙如果两个int类型的表达式表示相同的整数值,则两个表达式被视为相等。
∙如果两个object类型的表达式都引用同一对象或者都为null,则两个表达式被视为相等。
∙如果两个string类型的表达式的字符串实例的长度相同并且每个字符位置中的字符也相同,或者都为null,则两个表达式被视为相等。
示例
usingSystem;
classTest
{
staticvoidMain(){
strings="Test";
stringt=string.Copy(s);
Console.WriteLine(s==t);
Console.WriteLine((object)s==(object)t);
}
}
产生输出
True
False
这是因为第一个比较的是两个string类型的表达式,而第二个比较的是两个object类型的表达式。
1.2.2转换
预定义类型还具有预定义的转换。
例如,在预定义类型int和long之间定义了转换方法。
C#区分两种转换:
“隐式转换”和“显式转换”。
隐式转换仅适用于那些不用仔细检查即可安全地实现的转换。
例如,从int到long的转换是隐式转换。
这种转换总是会成功,而且从不会导致信息丢失。
在以下示例中:
usingSystem;
classTest
{
staticvoidMain(){
intintValue=123;
longlongValue=intValue;
Console.WriteLine("{0},{1}",intValue,longValue);
}
}
类型int转换为long是隐式地实现的。
相反,显式转换需用强制转换表达式(cast)来实现。
在以下示例中:
usingSystem;
classTest
{
staticvoidMain(){
longlongValue=Int64.MaxValue;
intintValue=(int)longValue;
Console.WriteLine("(int){0}={1}",longValue,intValue);
}
}
类型long转换为int是显式转换,它使用了强制转换表达式。
输出为:
(int)9223372036854775807=-1
这是因为有溢出发生。
强制转换表达式既可用于显式转换亦可用于隐式转换。
1.2.3数组类型
数组可以是一维或多维的。
“矩形”排列的和“交错形”排列的数组都受支持。
一维数组是最常见的类型。
示例
usingSystem;
classTest
{
staticvoidMain(){
int[]arr=newint[5];
for(inti=0;i arr[i]=i*i; for(inti=0;i Console.WriteLine("arr[{0}]={1}",i,arr[i]); } } 创建一个由int值构成的一维数组,初始化数组元素,然后将它们每个都打印出来。 产生的输出为: arr[0]=0 arr[1]=1 arr[2]=4 arr[3]=9 arr[4]=16 前面示例中使用的int[]类型即为一种数组类型。 数组类型是用一个非数组类型名称后跟一个或多个秩说明符来表示的。 示例 classTest { staticvoidMain(){ int[]a1;//single-dimensionalarrayofint int[,]a2;//2-dimensionalarrayofint int[,,]a3;//3-dimensionalarrayofint int[][]j2;//"jagged"array: arrayof(arrayofint) int[][][]j3;//arrayof(arrayof(arrayofint)) } } 显示了一些局部变量,声明了一些属于以int作为元素的数组类型的不同变型。 数组类型为引用类型,因此数组变量的声明只是为数组引用留出空间。 数组实例实际上是通过数组初始值设定项和数组创建表达式创建的。 示例 classTest { staticvoidMain(){ int[]a1=newint[]{1,2,3}; int[,]a2=newint[,]{{1,2,3},{4,5,6}}; int[,,]a3=newint[10,20,30]; int[][]j2=newint[3][]; j2[0]=newint[]{1,2,3}; j2[1]=newint[]{1,2,3,4,5,6}; j2[2]=newint[]{1,2,3,4,5,6,7,8,9}; } } 显示了各种数组创建表达式。 变量a1、a2和a3表示“矩形数组”,而变量j2表示“交错形数组”。 这些术语基于数组的形状,这一点不足为奇。 矩形数组总是具有矩形形状。 已知数组每个维度的长度,它的矩形形状就很清楚了。 例如,a3的三个维度的长度分别是10、20和30,很容易就可以看出此数组包含10*20*30个元素。 相反,变量j2表示一个“交错的”数组或“数组的数组”。 具体说来,j2表示int数组的数组,即类型int[]的一维数组的数组。 这些int[]变量中的每一个都可以单独初始化,这就允许数组采用交错形状。 此示例给每个int[]数组提供了一个不同的长度。 具体说来,j2[0]的长度为3,j2[1]的长度为6,j2[2]的长度为9。 在C++中,用intx[3][5][7]声明的数组会被视为三维矩形数组,而在C#中,int[][][]声明的是一个交错的数组类型。 数组的元素类型和数组的形状(交错形还是矩形,以及它的维数)是数组类型定义的组成部分。 另一方面,数组的大小(由它的每个维度的长度表示)却不是数组类型定义的组成部分。 C#语法明确地规定了这个区别,数组的每个维的长度需在数组创建表达式中指定,而不能在数组类型声明中指定。 例如,声明 int[,,]a3=newint[10,20,30]; 包含了一个数组类型int[,,]和一个数组创建表达式newint[10,20,30]。 对于局部变量和字段的声明,允许使用简写形式,因此没有必要再次声明数组类型。 例如,示例 int[]a1=newint[]{1,2,3}; 可以简写为 int[]a1={1,2,3}; 它们具有完全相同的程序语义。 从数组初始值设定项(如{1,2,3})所处的上下文可以确定该数组的类型。 示例 classTest { staticvoidMain(){ short[]a={1,2,3}; int[]b={1,2,3}; long[]c={1,2,3}; } } 显示同一数组初始值设定项语法可用于多种不同的数组类型。 由于需要根据所处的上下文来确定数组初始值设定项的类型,因此,数组初始值设定项不能用于其所处的上下文中没有关于数组类型的显式声明的表达式中。 1.2.4类型系统统一化 C#提供了一个“统一类型系统”。 所有类型(包括值类型)都是从object类型派生的。 这样,类型Object中定义的方法就可以在任何值类型的值(甚至是像int这样的“基元”类型的值)上调用。 示例 usingSystem; classTest { staticvoidMain(){ Console.WriteLine(3.ToString()); } } 从整数值3调用object定义的ToString方法,产生输出“3”。 示例 classTest { staticvoidMain(){ inti=123; objecto=i;//boxing intj=(int)o;//unboxing } } 更有趣。 一个int值可以转换为object,并可再次转换回int。 此示例同时显示了“装箱”和“取消装箱”。 当值类型的变量需要转换为引用类型时,执行“装箱”,即设置一个对象箱来保存值这个值(该值被复制到箱中)。 “取消装箱”则正好相反。 当对象箱被强制转换回其原来的值类型时,该值就从箱中取出并复制到适当的存储位置。 此类型系统统一化为值类型提供了对象性的优点,并且不会带来不必要的系统开销。 对于不需要int值的行为与对象一样的程序,int值只是32位值。 对于需要int值的行为与对象一样的程序,可以根据需要使用此功能。 这种将值类型作为对象处理的能力弥补了大多数语言中存在的值类型与引用类型之间的差距。 例如,Stack类可以提供Push和Pop方法,这些方法获得并返回一个object值。 publicclassStack { publicobjectPop(){...} publicvoidPush(objecto){...} } 由于C#具有统一类型系统,因此Stack类可以与任何类型的元素一起使用,其中包括像int这样的值类型。 1.3变量和参数 变量表示存储位置。 每个变量都属于一种类型,它确定什么样的值可以存储在该变量中。 局部变量是在方法、属性或索引器中声明的变量。 局部变量是通过指定类型名称和声明符(它指定变量名和可选的初始值)定义的,如: inta; intb=1; 但局部变量声明也可以包含多个声明符。 a和b的声明可以重写为: inta,b=1; 一个变量必须先赋值,然后才能使用它的值。 示例 classTest { staticvoidMain(){ inta; intb=1; intc=a+b;//error,anotyetassigned ... } } 导致编译时错误,因为它试图在给变量a赋值之前使用它。 第5.3节中定义了关于如何明确地赋值的规则。 字段(第10.4节)是与类或结构或与类或结
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C#