Response.Write("iandj:
"+i+"+"+j);
缺省空白
在for中初始部分、条件、重复变化部分,都可以为空
如:
for(i=0;i<10;)
在循环体内部进行i运算
for(;i<10;)
必须事先初始化i,在循环体内部进行i运算
for(;;)
无限循环
没有循环体的循环
例如:
对1至50累加:
intsum=0;
for(i=1;i<=50;sum+=i++);
在循环体只有一条语句时,完全可以采用这种方法。
for(;DataReader1.read();Response.Write(DataReader1["name"]));
while循环
while(条件)
{循环体}
条件为真时执行
do-while循环
do
{循环体}
while(条件)
do-while循环是在未尾判断条件,这意味着循环至少会被执行一次,在某些情况下可以减少代码量。
break
利用break可以强制跳出循环,并略过本次循环的剩余代码。
Continue
略过本次循环的剩余代码,提前进入下一次循环。
goto跳转
无条件跳转到指定位置,如:
loop1:
//标签,标签后跟冒号
x++;
if(x<10)gotoloop1;//无条件跳到loop1处
goto鼓励创造无头绪代码,然而有时却能使程序更加清晰和便捷,比如从深层嵌套中退出。
foreach循环
foreach(类型形参变量in数组或集合){
}
形参变量必须与数组集合的基本类型相同或兼容
foreach也可用于多维数组,遍历其中的第一维,按照行的顺序从头到尾返回减少了一维的子数组。
继承
继承
首先建立一个通用类,定义出公用的特性。
可以被其他更具体的新类继承,在每个新类中都添加特有的性质。
那么,被继承的类叫做基类,继承后产生的类叫做派生类。
因此,派生类是基类的特殊版本。
它继承了基类的所有变量、方法、属性和基类定义的索引。
继承声明
C#类声明中允许集成另一个类,这要通过声明派生类时指定基类来完成。
如:
class派生类名:
基类名{
}
尽管派生类继承自基类,但它完全是一个独立的类。
而基类也完全可以按照独立类来使用。
你只能为任何一个新建的派生类指定一个基类,C#不允许多个基类共同派生出一个新。
然而派生类可以作为另一个派生类的基类。
派生类无法继承基类的private私有成员。
但我们有其它方法来访问基类的私有成员:
protected访问修饰符和用属性来访问私有数据。
protected访问修饰符
protected保护成员在类的层次结构外被认为是私有成员。
类成员被声明为protected后实际上是私有的,但它会被继承到派生类,因此可以被派生类访问。
构造函数的继承性
基类的构造函数构造对象的基类部分,派生类的构造函数构造对象的派生类部分(后来添加的方法和变量)。
构造函数的构造过程是分开的。
在类的层次中,构造函数按照派生的顺序,从基类到派生类调用。
而且无论是否使用base都会采用这种顺序。
隐藏
个人认为叫遮盖更贴切一点。
派生类有可能定义和基类中名字相同的成员,此时,基类中的同名成员就会被隐藏。
这并不算异常,但编译器会给出警告,提示你该成员被隐藏了。
如果要隐藏基类成员并取消编译器警告,声明成员时要在前面加上new关键字(这与创建对象实例截然不同)。
格式:
new类型成员名;
关键字base
关键字base有两个用途:
1.调用基类的构造函数
2.访问派生类覆盖的基类成员
调用基类的构造函数
构造函数名(参数列表):
base(参数列表){
}
base指的是调用类的上一级基类,如果没有base语句就自动调用基类缺省的构造函数
如:
classa{
intt,n;
publica(intx,inty){
t=x;n=y;
}
}
classb:
a{
ints;
publicb(inti):
base(i,9){//可以直接使用形参i,像在函数内部一样。
s=i;
}
}
访问(被隐藏的)基类成员
用法类似于this,只不过它引用的是基类。
用法:
base.成员名
方法、实例变量、属性均可。
base.show();//引用基类的show()方法
引用与继承
一个类型的引用变量通常不能引用另一个类类型的对象。
(除了类型兼容外)
可是,C#允许基类的引用变量赋给该基类的任何一个派生类的对象。
但此时只能访问基类中已定义的基类成员,因为基类不知道派生类添加的信息。
虚方法和重载
个人认为所谓虚方法,就是可以被派生类覆盖的方法。
(这与用new隐藏一个基类方法有什么不同?
)
基类中将一个方法声明前加上关键字virtual,该方法就被认为是虚方法。
当派生类重新定义虚方法时,就要使用override修饰符。
这种派生类重新定义虚方法的过程被称为方法重载。
虚方法不能被定义为static或abstract。
方法重载形了C#的一个重要概念:
动态方法分配。
动态方法分配是一种在程序运行时,而不是在编译时调用重载函数的机制。
运行期多态就是靠它实现的
抽象类与抽象方法
抽象类:
相当于只定义一个被所有派生类共享的基本形式,派生类实现类的功能细节。
抽象类不能实例化对象,否则会导致编译错误。
abstractclass类名{
}
抽象方法:
相当于一个没有被代码实现的虚方法(但virtual和abstract一起使用是错误的)
abstract返回类型方法名(参数列表);
不能将静态方法设置的抽象方法
包括抽象方法的类必须也声明的抽象类
当一个派生类继承了一个抽象类时,该类就必须实现基类的所有抽象方法,除非这个派生类也是abstract抽象类,则其中的抽象方法就可以不用实现而继续的继承下去。
封装
使用封装可以防止一个类被继承。
关键字sealed用于实现封装。
在类声明前加上sealed即可,但一个类声明中不能既有abstract又有sealed。
sealedclassA{}
object类
所有的类皆派生于object类(System.Object)。
也就是说object是任何类型的“兼容类型”。
这意味着,类型为object的引用变量可以引用其他任何类型的对象。
object中的方法
方法
目的
publicvirtualboolEquals(object对象名)
决定当前对象是否和object的引用相同
publicstaticboolEquals(object对象1,object对象2)
决定对象1是否和对象2指向同一个对象
publicvirtualintGetHashCode()
返回当前对象相关的散列码
publicTypeGetType()
运行时获取对象的类型
publicstaticboolReferenceEquals(object对象1,object对象2)
决定对象1是否和对象2指向同一个对象
publicvirtualstringToString()
返回描述对象的字符串
装箱:
当一个“object类引用”引用了值类型时,就发生了装箱操作。
装箱使得值类型的数值被存到对象实例中。
被“装”在object类型中,像对象一样被使用。
装箱操作是自动进行的,你只需赋值给object类型的引用。
拆箱:
是从对象获取值类型的过程。
这个操作执行了从object类型引用到期望的值类型的转换。
x=10;
obj=x;//x被装箱到对象中
inty=(int)obj;//对象obj被拆箱到整型变量中
接口
接口相当于只定义了类的结构,但没有定义类的实现细节。
接口中没有一个方法和实体,无论如何接口都不会提供实现细节。
一个接口可以被许多类继承并实现,一个类也可以继承并实现许多接口。
接口方法
声明格式:
interface接口名{
返回类型方法名{参数列表};
返回类型方法名{参数列表};
返回类型方法名{参数列表};
}
包含接口的类必须实现所有的方法。
接口中的方法默认为public,不用显式指明。
继承接口:
class类名:
接口名{
}
接口引用
你可以创建接口引用变量。
只能先建立实现接口的类的实例,然后将类实例转换为接口类型,不能用new构造接口实例。
一般情况下,采用将类实例转换为接口引用来访问接口是一种更好的接口访问方式,不过很多情况下,我们不知道对象是否支持某个接口,这时,可以试图将对象转换为接口处理,并利用try/catch进行判断处理。
接口属性
声明格式:
interface接口名{
类型属性名{
get;
set;
}
}
接口索引:
声明格式
interface接口名{
返回类型this[int变更名]{
get;
set;
}
}
接口继承接口
一个接口可以继承另一个接口,语法和继承类的一样:
publicinterfaceB:
A{
}
显式实现接口
也就是写清全名,如在继承了接口的类中使用“接口名.成员名”的方式
interfaceA{
intNa();
}
classB:
A{
intA.Na(){//接口的显式实现
Response.write("已执行");
}
}
原因有二:
一个类有可能同时实现了两个接口,如此可处理同名成员。
当使用全称作用域实现一个方法时,就相当于提供了不是处于类外代码的一个私有实现。
(意思是否指这个方法实质上不属于定义它的类)
结构
类是引用类型,值类型可以被直接访问。
结构颇似于类,但它是值类型。
使用关键字struct声明结构:
struct结构名称:
接口名称{
//成员声明
}
结构不能继承其他结构或类,也不能被类继承。
可是,结构能够用来实现一个或多个接口(用逗号分隔)。
structaccount{
publicstringname;
publicdoublebalance;
publicaccount(stringn,doubleb){
name=n;
balance=b;
}
}
类(对象与方法)
类是一种抽象的逻辑,一个设计合理的类应该只包含一个逻辑实体。
类组织那些逻辑上有联系的信息。
把逻辑上无关的信息放在同一个类中会破坏代码的一致性。
在技术上,在有创建了类的对象实例,类才物理的体现在内存中。
构建类的变量和方法都称作该类的成员。
类为引用类型。
类的形式
当你在程序中定义一个类时,你声明了该类应当包含的数据和操作这些数据的代码。
定义类:
class类名
{
//访问修饰符类型成员名;
publicintmpg;
}
定义一个类实际上就是创建了一个新的数据类型
当在一个类中使用类成员时,可以直接使用,而不必使用点运算符,因为类也是一个作用域。
Main程序入口方法
Main()和Page_Load()方法一样,是一个类中会自动运行的方法,但一般形式的类并不指定Main()方法,只有当你的类是程序的入口点时才有必要这样做。
Main()方法是一个应用程序的入口,当它所在的类是程序的入口点时,该方法会在应用程序启动时自动执行。
从Main()返回值
当程序结束时,可以通过Main()向调用它的程序(通常是操作系统)返回一个值。
publicstaticintMain();
按惯例,返回值为0通常表示程序正常终止。
返回其他值都表示出现了某种类型的错误。
向Main()传递参数
许多程序都接收命令行参数。
命令行参数是在命令行中直接跟在程序名后面的信息(如:
format-q-s)。
对于C#程序,这些参数都会传递给Main()方法。
为了接收这些参数,必须使用如下的Main()形式:
publicstaticintMain(string[]args);//接收到的是一个字符串数组
对象的创建
格式:
访问修饰符类对象名=new构造函数();
publicCarmyCar=newCar();
此处,该声明创建了对象的实际物理拷贝,并把它赋值给myCar变量以引用对象(myCar只是一个引用变量)。
new运算符为对象动态分配内存,并返回该对象的一个引用,这个引用是用new分配到的对象的内存地址。
方法
格式:
访问修饰符返回值类型方法名(参数列表)
publicintaddNum(inta,doubleb)
{
returna+b;
//方法体;
}
其中,返回值类型是指该方法返回数据的类型,它可以是任何有效类型(类也是数据类型)。
参数列表是用逗号隔开的类型、标识符对。
形参本质上是变量,它用来在调用方法时接收实参传来的值(形参只在方法内部有效)。
如没有参数接收为空即可。
如果参数为值类型,则形参为其值的copy,
如果参数为对象类型,则形参为其对象引用。
return
return用于从方法返回一个值给调用者。
返回数据类型必须与该方法定义时指定的返回数据类型相一致。
用于从方法返回一个值并跳过剩余代码,或在void方法中起到提前结束方法的作用。
(可以使用多个return以应对多个分支)
returnnewErr(errInfo);//构造并返回对象
一般而言,带有返回值的方法可以参与表达式的运算。
ref参数
使方法传递参数时,可以作为引用来接收实参,这样方法就有能力改变实参本身的值了。
注:
实参在调用前必须赋值,不能用方法给使用ref的实参赋初值。
sqr(refinti){
i=i*i;
}
...
inta=10;
sqr(refa);
a值变为100
out参数
out与ref参数功能相同,唯一区别是:
实参在调用前不必赋值,可以用方法给使用out的实参赋初值。
sqr(outinti){
i=10;
i=i*i;
}
...
inta;
sqr(outa);
a值变为100
ref与out参数支持原本就是引用类型的实参,得到的是引用变量本身,而不新建一个变量。
这样我们就可以在方法中改变“实参引用变量”所指的对象了。
可变数量的参数
方法的形参中params修饰符用来声明一个数组参数,这个数组参数可以接收0个或多个实参。
该数组长度与所传递实参个数相同。
(说白了就是接收一个数组)
voidshowArgs(stringmsg,paramsint[]nums){
...
}
showArgs("test",1,2,3,4,5);
当方法既有正规参数又有params参数时,params参数必须位于参数表的最后面。
而且,在任何情况下都只能有一个params参数。
方法重载
在C#中,只要它们的参数声明的不同,同一个类中的两个或更多方法可以拥有相同的名字,这种情况就称为方法的重载,重载可以使一个方法适应多种不同的传参情况。
每个重载的方法,参数类型和个数必须不同。
但是可以有不同的返回值类型。
构造函数
构造函数在对象创建时初始化对象。
它和类的名字相同,语法上类似方法,区别是没有返回值。
定义格式
访问修饰符类名()
{
//构造函数代码
}
你可以使用构造函数给类中所定义的实例变量赋一个初值,或者执行一些在创建对象时就必需执行的初始化操作。
在没有定义构造函数的情况下,C#自动定义一个缺省的构造函数来把类中定义的实例变量初始化为0(对于值类型)或null(对于引用类型)。
但是,一旦你定义了自己的构造函数,缺省的构造函数就不再使用。
当一个对象被创建时,该构造函数被new调用,如:
MyClassti=newMyClass();
注:
构造函数通常被指定为public,这是因为它要被外部代码调用,用以构造一个类。
(当没有足够内存时new可能不能为一个对象实例分配内存。
否则将发生异常,我们实际编程时还是有必要注意这种可能性的。
)
构造函数中可以使用return来跳过剩余代码
值类型也可以使用构造函数:
inti=newint();
带参数的构造函数:
如果你的构造函数需要接收参数,可以用与方法接收参数格式相同的语法:
ClassMyClass{
publicintx,y;
publicMyClass(inti,intn){
x=i;y=n;
}
}
MyClasst1=newMyClass(10,9);//调用构造函数
构造函数的重载
在C#中,只要它们的参数声明的不同,同一个类中可以有多个构造函数,这种情况就称为构造函数的重载,重载可以使构造函数适应多种不同的传参情况。
通过this用一个构造函数调用另一个
构造函数(参数列表):
this(匹配的形参);
ClassXYCoord{
publicintx,y;
publicXYCoord(inti,intj){
Console.WriteLine("InsideXYCoord");
x=i;
y=j;
}
publicXYCoord():
this(0,0){
Console.WriteLine("InsideXYCoord");
}
publicXYCoord(XYCoordobj):
this(obj.x,obj.y){
Console.WriteLine("InsideXYCoord");
}
}
其中this(0,0)相当于调用XYCoord(0,0),系统自动匹配到XYCoord(inti,intj)。
而XYCoord的实例obj.x和obj.y也是int型,所以依然自动匹配到XYCoord(inti,intj)。
通过this调用重载构造函数很有用,原因之一是它避免了不必要的代码重复,第二是方便方法更好的适应带有“隐含实参”的构造函数,以使构造函数可以在实参没有明确指明的情况下使用。
垃圾回收
new运算符可在内存池中动态的为对象分配内存,而C#的垃圾回收系统则自动回收对象占用的内存。
其工作原理:
当一个对象没有对其的引用存在时,该对象就被认为不再需要了。
垃圾回收是偶尔发生的,且其工作耗时,系统只会在有必要的情况下经行回收,因此你不可能精确知道垃圾回收是什么时候发生的。
析构函数
个人认为析构函数相当于一个事件,在对象即将被垃圾回收前调用,在其中你可以指定那些必须在对象销毁前完成的行为。
格式:
~Class-name(){//是否支持参数传入?
//操作
}
记住,有可能程序在垃圾回收以前就结束了,在这种情况下析构函数根本不会被调用。
this关键字
当调用一个方法时,自动传递一个隐含的参数,该参数引用调用对象,其引用参数为this 。
类成员的访问
实际上成员只有两大基本访问类型:
共有和私有
访问修饰符:
public、private、protected、internal。
如果不定义任何修饰符,一个类成员会被默认为private
同一个类的成员可以访问类中的私有成员
Main()方法
Main()方法是一个应用程序的入口,当它所在的类是程序的入口点时,该方法会在应用程序启动时自动执行。
从Main()返回值
当程序结束时,可以通过Main()向调用它的程序(通常是操作系统)返回一个值。
publicstaticintMain();
按惯例,返回值为0通常表示程序正常终止。
返回其他值都表示出现了某种类型的错误。
向Main()传递参数
许多程序都接收命令行参数。
命令行参数是在命令行中直接跟在程序名后面的信息(如:
format-q-s)。
对于C#程序,这些参数都会传递给Main()方法。
为了接收这些参数,必须使用如下的Main()形式:
publicstaticintMain(string[]args);//接收到的是一个字符串数组
递归
递归是一个用本身去定义它自己的过程。
递归方法的关键是它包含一个调用自身的语句。
理解静态static
当成员声明为static时,不需要通过对象对其进行访问,对它的访问可以发生在类的任何对象创建之前。
方法和变量都可以声明为static。
最普通的static成员的例子是Main()方法。
在类外使用static成员必须指明类的名字。
static成员不能通过对象实例来访问,它必须通过类名进行访问。
除了使用类名外,其格式与通过对象访问普通类成员相似。
static静态变量
被声明为static的变量是全局变量,static变量在类被装载时初始化。
如果没有明确的初始化设置,数值类型将被初始化为0,引用变量(包括string)初始化为空,bool变量初始化为false。
因此,static变量总有一个值。
static静态方法有几点限制
1.static方法不能引用this。
2.static方法只能直接调用其他static方法。
它不能调用类中的实例方法。
原因是实例方法作用于类中的特定实例,但static方法不是。
3.static方法只能直接访问static数据。
它不能使