2.c#编程概述:
【1】标识符:字符串,用来命名如变量、方法、参数等。
【2】关键字:用来定义c#语言的字符串记号,如int,if,abstract等。
【3】空白:空白字符包括空格(space);制表符(tab);换行符;回车符。
【4】注释:单行注释 //abc , 带分隔符注释 /* abc*/ ,文档注释///abc。
3.类型、存储和变量:
【1】命名空间是一种把相关的类型声明分组并命名的方法。
【2】预定义类型(使用时直接实例化):C#提供了16种预定义类型,名称由全小写字母组成。分为简单类型(13种)和非简单类型(3种)。
简单类型有:sbyte,byte(8bit)、short,ushort(16bit)、int,uint(32bit)、long,ulong(64bit)、float,double,bool,char,decimal。
非简单类型有:object,string,dynamic。
【3】用户定义类型(使用时先声明后实例化):类类型(class);结构类型(struct);数组类型(array);枚举类型(enum);委托类型(delegate);接口类型(interface)。
【4】栈:是一个内存数组,是一个后进先出的数据结构。
堆:是一块内存区域,与栈不同,堆里的内存能够以任意顺序存入和移除,是一种先进先出的数据结构。
【5】值类型数据存放在栈里;引用类型数据存放在堆里其引用存放在栈里。对于一个引用类型,其实例的数据部分始终存放在堆里。既然两个成员都是对象数据的一部分,那么它们都会被存放在堆里,无论它们是值类型还是引用类型。
【6】c#类型的分类
| 值类型 | 引用类型 |
预定义类型 | sbyte byte float short ushort double int uint char long ulong decimal bool | object string dynamic |
用户定义类型 | struct enum | class interfac delegate array |
【7】变量类型
变量类型 | 存储位置 | 自动初始化 | 用途 |
本地变量 类字段 结构字段 参数 数组元素 | 栈或者栈和堆 堆 栈或堆 栈 堆 | 否 是 是 否 是 | 用于函数成员内部的本地计算 类的成员 结构的成员 用于把值传入或者传出方法 数组的成员 |
【8】可空类型:int? myint = 28;可空类型允许创建可以标记为有效或者无效的值类型,这样就可以在使用它之前确定值的有效性。
【9】静态类型:变量的类型在编译的时候确定并且不能在运行的时候修改。
dynamic关键字代表一个特定的,实际的c#类型,它知道如何在运行时解析自身。也就是说,它是动态化的静态类型。这样就可以配合程序集中其他的有动态类型的脚本语言使用
4.类:基础
【1】类是一个能存储数据并执行代码的数据结构。它包含两个
数据成员:
字段和常量,以及七个
函数成员:
方法、
属性、构造函数、析构函数、
运算符、索引和
事件。
【2】类的声明定义新类的特征和成员,它并不创建类的实力,但创建了用于创建实例的模板。类成员可以在类的主体内部以任何顺序声明,这意味着成员的声明完全可以引用另一个在后面的类声明中才定义的成员。(因为累声明“定义”了一个新类,所以经常会在文献和程序员的日常使用中看到类声明被称为“类定义”)。
【3】字段是隶属于类的变量,它可以是任何类型,无论是预定义类型还是用户定义类型。与c和c++不同,c#在类型的外部不能声明全局变量(也就是变量或字段)。所有的字段都属于类型,而且必须在类型声明内部声明。
【4】类是引用类型,这意味着它们腰围数据引用和实际数据两者都申请内存。要创建类的实例,需要从声明一个类类型的变量开始。如果变量没有被初始化,它的值是未定义的。
【5】声明类类型的变量所分配的内存是用来保存引用的,而不是用来保存类对象实际数据的。要为实际数据分配内存,需要使用new运算符。new运算符为任意指定类型的实例分配并初始化内存。它依据类型的不同从栈或堆分配。
【6】5种访问修饰符:private,public,protected,internal,protected internal。
5.方法
【1】和字段一样,本地变量也保存数据。字段通常保存和对象状态有关的数据,而创建本地变量经常是用于保存本地的或者临时的计算数据。
| 实例字段 | 本地变量 |
生存期 | 从实例被创建开始,直到实例不再被访问时结束 | 从它在块中被声明的那点开始,在块完成执行时结束 |
隐式初始化 | 初始化成该类型的默认值 | 没有隐式初始化,如果变量在使用之前没有被赋值,编译器就会产生一条错误信息 |
存储区域 | 类的所有字段都存储在堆里,无论它们是值类型还是引用类型的 | 值类型存储在栈里 引用类型的引用存储在栈里,数据存储在堆里 |
【2】var关键字并不是某种特别类型的符号。它只是句法上的速记,表示任何可以从初始化的右边推断出的类型。
使用
var关键字有一些重要的条件:
只能用于本地变量,不能用于字段;
只能在变量声明中包含初始化时使用;
一旦编译器推断出变量的类型,它就是固定且不能更改的。
【3】如同本地变量,本地常量必须声明在块的内部,且在声明中必须初始化,在声明后不能改变。
在类型之前加关键字const,必须有初始化语句,初始化值必须在编译期决定,它还可以是null引用,但它不能是某对象的引用,因为对象的引用是在运行时决定的。
【4】控制语句:
选择语句:这些语句可以选择哪条语句或语句块来执行。
if
有条件地执行一条语句;
if ...else
有条件地执行一条或多条语句;
switch
有条件地执行一组语句中的一条。
迭代语句:这些语句可以在一个语句块上循环或者迭代。
for
循环——在顶部测试;
while
循环——在顶部测试;
do
循环——在底部测试;
foreach
为一组中每个成员执行一次。
跳转语句:这些语句可以让你从代码块或方法体内部的一个地方跳到另一个地方。
break
跳出当前循环;
continue
到当前循环的底部;
goto
到一个命名的语句;
return
返回到发起调用的方法。
【5】方法要返回值时,方法必须在方法名前面声明一个返回类型;如果方法不返回值,它必须声明void返回类型。
有返回值的方法必须包含返回语句。void方法不需要返回语句。
可以在任何时候使用 return;返回语句退出方法,不带参数。这种形式的返回语句只能用于声明为void类型的方法。’
【6】形参是声明在方法的参数列表中而不是方法体中的本地变量。参数列表可以有任意数目的形参声明,而且声明必须用逗号分开。
实参是用于初始化形参的表达式或变量,位于方法调用的参数列表中。每一个实参必须与对应形参的类型相匹配,或者编译器必须能够把实参隐式转换为那个类型。
实参的数量必须和形参的数量一致(除非是params参数)。这种形式的参数叫
位置参数。
【7】值参数:使用值参数,通过
复制实参的值到形参的方式把数据传递到方法。方法被调用时,系统做如下操作:
在栈中为形参分配空间,复制实参到形参。
一个值参数的实参不一定是变量,它可以是任何能计算成相应数据类型的表达式。在把变量用做实参之前,变量必须被赋值。
所谓值类型就是指类型本身包含其值,不要把值类型和值参数混淆,它们是完全不同的两个概念。值参数是实参值复制给形参的参数。
引用类型: 使用引用参数时,必须在方法的
声明和调用中都使用
ref修饰符。
实参必须是变量(不能是表达式),在用做实参前必须被赋值。
形参的参数名看起来就好像是实参变量的
别名,也就是说,它们指向的是相同的内存位置。由于形参名和实参名的行为就好像指向相同的内存位置,所以在方法的执行过程中对形参作的任何改变在方法完成后依然有效(表现在实参变量上)。
输出参数:输出参数用于从方法体内把数据传输到调用代码,它们非常类似引用参数。
必须在方法的
声明和调用中都使用
out修饰符。
实参必须是变量(不能是表达式)。
就像引用参数,输出参数的形参担当实参的
别名,方法内对形参的任何改变在方法执行完成之后通过实参变量都是可见的。
在方法内部,
输出参数在被读取之前必须被赋值。这意味着参数的初始值是无关的,而且没有必要在方法调用之前为实参赋值。
参数数组:参数数组允许零个或多个实参对应一个特殊的形参。
在一个参数列表中只能有一个参数数组,如果有它必须是列表中的最后一个,使用
params修饰符
声明。在
调用中不允许使用params修饰符。
当数组在堆中被创建是,实参的值被复制到数组中,在这方面,它们像值参数。
【8】方法重载:一个类中可以有一个以上的方法拥有相同的名称,这叫做方法重载。使用相同名称的每个方法必须有一个和其他方法不相同的签名。
签名:方法的名称;参数的数目;参数的数据类型和顺序;参数修饰符。(返回类型不是签名的一部分,形参也不是签名的一部分)
【9】命名参数 :只要显示指定参数的名字,就可以任意顺序在方法调用中列出实参。如c.Calc(c:2,a:4,b:3); 在调用的时候,你可以既使用位置参数又使用命名参数,但是所有位置参数必须先列出来。
【10】可选参数:所谓可选参数就是我们可以在调用方法的时候包含这个参数,也可以忽略它。
为了表明某个参数是可选的,你需要在方法声明的时候为参数提供默认值。如:public int Calc(int a,
int b=3){return a+b;}
所有必填参数必须在可选参数声明之前声明,如果有params参数,必须在所有可选参数之后声明。
你必须从可选参数列表的最后开始省略,一直到列表开头。如果需要随意省略可选参数,那么必须使用可选参数的名字来消除赋值的歧义,也就是说需要结合利用命名参数和可选参数特性。
| 值 | ref | out | params |
值类型 | 是 | 否 | 否 | 否 |
引用类型 | 只允许null的默认值 | 否 | 否 | 否 |
【11】递归:方法调用自身。
6.类进阶
【1】类成员分类:1. 数据成员(保存数据):字段、常量 2.函数成员(执行代码):方法、属性、运算符、索引、事件、构造函数、析构函数。
【2】从类的外部访问静态成员:就像实例成员,静态成员也可以使用点运算符从类的外部访问。但因为没有实例,所以必须使用类名,如下面代码所示:D.Mem2 = 5;
如同静态字段,静态函数成员独立于任何类实例。即使没有类的实例,仍然可以调用静态方法。静态函数成员不能访问实例成员。然而,它们能访问其他静态成员。
能被声明为静态成员的类成员有:字段,方法,属性,构造函数,运算符,事件。
【3】成员常量:就像本地常量,只是它们被声明在类声明中;用于初始化成员常量的值在编译器必须是可计算的,而且通常是一个预定义简单类型或由它们组成的表达式;不能在成员常量声明以后给它赋值;与c和c++不同,在c#z中没有全局常量,每个常量都必须声明在类型内。
成员常量表现的就像静态变量,它们被类的每个实例都是“可见的”,而且即使没有类的实例它们也可以使用。与真正的静态量不同,常量没有自己的存储位置。
【4】属性: 属性是代表类的实例或者类中的一个数据项的成员。
就像字段,属性有如下特征:它是命名的类成员,它有类型,它可以被赋值和读取。然而和字段不同,属性是一个函数成员。
它不为数据存储分配内存!它执行代码。
属性是指定的一组两个匹配的、成为访问器的方法。set访问器用于为属性赋值,get访问器用于为属性获取值。get访问器的所有执行路径必须包含一条return语句,返回一个属性类型的值。不能显示的调用访问器。
惯例是在类中将字段声明为private以封装一个字段,并声明一个public属性以供受控的从类外部对字段的访问。和属性关联的字段常被称为后备字段或后备存储。
然而属性并非必须和字段关联。
自动实现属性:不声明后备字段,编译器根据属性的类型分别存储;不能提供访问器的方法体,它们必须被简单地声明为分号。除非通过访问器,否则不能访问后备字段。因为不能用其他的方法访问,所以实现只读和只写属性没有意义,因此必须同时提供读写访问器。
属性也可以声明为static。静态属性的访问器和所有静态的成员一样。
【5】实例构造函数:实例构造函数是一个特殊的方法,它在类的每个新实例创建的时候执行。构造函数用于初始化类实例的状态。如果希望能从类的外部创建类的实例,需要声明构造函数为public 。构造函数可以带参数,可以被重载。如果在类的声明中没有显示地提供实例构造函数,那么编译器会提供一个隐式的默认构造函数,它不带参数,它的方法体为空。如果你为类声明了任何构造函数,那么编译器将不会为该类定义默认构造函数。
构造函数也可以声明为static。区别是实例构造函数初始化类的每个新实例,而static构造函数初始化类层次的项目。通常,静态构造函数初始化类的静态字段。
和实例构造函数一样,静态构造函数的名称必须和类名相同。构造函数不能返回值。不同之处在于,静态构造函数声明中使用static关键字。类只能有一个静态构造函数,而且不能带参数。静态构造函数不能有访问修饰符。
类既可以有静态构造函数也可以有实例构造函数,不能从程序中显示调用静态构造函数,它们有时被系统自动调用。
对象创建表达式由关键字new后面跟着一个类构造函数及其参数表组成。对象初始化列表扩展了创建语法,在表达式的尾部放置了一组成员初始化列表。这允许你在创建新的对象实例时,设置字段和属性的值。