C#学习精华.docx
《C#学习精华.docx》由会员分享,可在线阅读,更多相关《C#学习精华.docx(33页珍藏版)》请在冰豆网上搜索。
C#学习精华
以下任何一条,就应该使用类:
1.需要派生其他类型。
2.需要继承。
3.该类型作为方法参数传递。
因为结构是值类型,每次调用都要创建结构的副本。
但结构放在数组中例外。
4.该类型用作方法的返回类型。
(3)枚举成员默认值
在枚举类型中声明的第一个枚举成员它的默值为零。
以后的枚举成员值是将前一个枚举成员(按照文本顺序)的值加1得到的。
这样增加后的值必须在该基础类型可表示的值的范围内;否则,会出现编译时错误。
示例:
publicenumTimeofDay:
uint
{
Morning,
Afternoon,
Evening
}
Morning的值为0,Afternoon的值为1,Evening的值为2。
(4)为枚举成员显示赋值
允许多个枚举成员有相同的值.
没有显示赋值的枚举成员的值,总是前一个枚举成员的值+1.
示例
publicenumNumber
{
a=1,
b,
c=1,
d
}
b的值为2,d的值为2.
注意:
以上枚举值都不能超过它的基础类型范围。
否则会报错.
示例:
publicenumNumber
{
a,
b,
c,
d
}
classTest
{
publicstaticvoidMain()
{
inti=Number.a;//错误,要强制类型转换(int)Number.a
Numbern;
n=2//错误,要强制类型转换(Number)2
}
线程
多线程难点(并发问题演示)如果只看上面,多线程实在是太简单啦,多个线程无非就是多new几次而已,但是这里面有个问题,就是如果线程访问同一个资源,如网络订票,一个客户买了票,另一个客户再买的话,按道理说应该不能买啦,但是线程是独立运行的,两个线程互不干扰,怎么让另一个线程知道自己访问资源已经被修改了,这就涉及到线程同步的问题啦,同时各种熟悉的概念死锁,并发也来啦。
修改程序代码如图所示。
因为设置的是随机等待时间,所以运行结果不同。
线程同步,线程同步也成为阻塞调用,即没有执行完任务不返回,线程被挂起。
可以使用C#中的lock关键字,在此关键字范围类的代码都将是线程安全的。
lock关键字需定义一个标记,线程进入锁定范围是必须获得这个标记。
当锁定的是一个实例级对象的私有方法时使用方法本身所在对象的引用就可以了。
修改代码如下,运行结果如图所示
数据输出(WriteWriteLine)
Console.Write()方法
Console.Write方法用来向控制台输出一个字符,但控制台的光标不会移到下一行。
其定义如下:
publicstaticvoidWrite(XXXvalue);
publicstaticvoidWrite(stringformat,objecto1,……);
注意:
格式化format同格式化函数Format中的格式化串类似,其格式如下:
{N[,M][:
formatstring]}
其中,字符N表示输出变量的序号,M表示输入变量在控制台中所占的字符空间,如果这个数字为负数,则按照左对齐的方式输出,若为正数,则按照右对齐方式输出。
//WriteTest.cs
usingSystem;
publicclassWriteTest
{
publicstaticvoidMain()
{
inti=32767;
doubled=456.56789;
//由控制台。
按照十进制输出整数及浮点数
Console.Write("i=0x{0,8:
X}\td={1,10:
F3}\t",i,d);
//由控制台。
按照十六进制输出整数
Console.Write("i=0x{0,-8:
X}\td={1,-10:
F3}\t",i,d);
Stringstr=Console.ReadLine();
Console.WriteLine(str);
Console.ReadLine();}
}
输出结果:
i=0x7FFFd=456.568i=0x7FFFd=456.568字符串
对象
类或结构的默认访问类型是internal。
类中所有的成员,默认均为private。
构造函数
构造函数是一种用于对象初始化的特殊方法,有以下特点。
–构造函数只能在对象创建时调用,即和new运算符一起被调用。
–构造函数和类具有相同的名字。
–构造函数可以有0个、1个或多个参数。
–构造函数没有返回值。
–每个类至少有一个构造函数,一个类可以有多个构造函数。
–如果没有为类定义构造函数,系统会自动为其定义一个缺省的构造函数。
缺省构造函数不带参数,作用是将实例变量都清零。
–一旦为类定义了构造函数,则系统不会再为其定义缺省构造函数。
C#中构造函数有三种:
实例构造,私有构造和静态构造
类名对象名=new构造函数(参数类表);
类的构造函数可通过初始值设定项来调用基类的构造函数,例如:
publicStudent(stringno,stringname,charsex,intage):
base(name,sex,age)
{…}
类的构造函数也可通过关键字this调用同一个类的另一个构造函数,例如:
publicPoint():
this(0,20)
{…}
classStudent
{
longid;
chargender;
intclassID;
publicStudent():
this(0,'F',0)
{}
publicStudent(longaID,charaGender,intaClassID)
{
id=aID;
gender=aGender;
classID=aClassID;
}
}
私有构造函数
在某些特殊的情况下,使用私有构造函数能够达到意想不到的效果。
比如,想建立这样一个类:
不允许被其他类实例化,但提供对外的静态接口成员。
在.NET框架类库中就存在这样的类,如System.Math类就不能够实例化,它的所有成员都是静态的。
用关键字private修饰的构造函数就是私有构造函数。
析构函数
C#支持析构函数。
虽然C#能够自动进行垃圾回收,但对于某些资源,.Net不知道如何回收,所以需要人工的内存回收。
在.net编程环境中,系统的资源分为托管资源和非托管资源。
–托管资源,如简单的int,string,float,DateTime等等,是不需要人工干预回收的。
–非托管资源,例如文件,窗口或网络连接,对于这类资源虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。
在使用完之后,必须显式的释放他们,否则会占用系统的内存和资源,而且可能会出现意想不到的错误。
.net中超过80%的资源都是托管资源。
静态构造函数
静态构造函数用于初始化类。
在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。
静态构造函数既没有访问修饰符,也没有参数。
无法直接调用静态构造函数。
在程序中,用户无法控制何时执行静态构造函数。
静态构造函数的典型用途是:
当类使用日志文件时,将使用这种构造函数向日志文件中写入项。
2).只读字段
当字段声明中包括readonly修饰符时,该字段成为只读字段。
只能在声明只读字段的同时赋初值。
其他任何时候都不允许为只读字段赋值。
publicclassClass1{
publicreadonlystringstr1=@”Iamstr1”;}
执行下面代码:
Class1c1=newClass1();
Console.WriteLine(c1.str1);
//c1.str1=“Changereadonlyfiled”;错误
如果在类定义中显式添加一个构造函数,可以在构造函数中改变只读字段的值。
PublicclassClass1
{Publicreadonlystringstr1=@”Iamstr1”;
publicClass1(){str1=“initializedbyconstructor!
”;}
}
2.方法成员
方法成员的本质就是在类中声明的函数,描述类能够“做什么”。
(1).方法声明格式
[访问修饰符]返回类型方法名称([参数列表])
{
方法体;
}
省略访问修饰符时,默认为private
例
usingSystem.Drawing;//第二种用这句
publicclassmyRect
{
Privateystem.Drawing.Pointp0;
//第二种用这句privatePointp0;
privateinta,b;
publicmyRect(intaa,intbb,System.Drawing.Pointp)
//第二种用这句publicmyRect(intaa,intbb,Pointp)
{
a=aa;b=bb;p0=p;
}
publicintArea()//求面积
{Return(a*b);}
publicintround()//求周长
{Return(2*(a+b));}
publicvoidmove(intdx,intdy)//移动顶点
{
p0.X+=dx;
p0.Y+=dy;
}
}
2).方法重载
重载规则:
方法名相同
方法的参数列表不同:
参数个数、参数数据类型
例如3-3,下面建立一个类Operate,该类有两个重载方法,分别对整型和浮点型做加法运算。
publicclassOperate
{
publiclongAdd(longa,longb)
{return(a*b);}
publicdoubleAdd(doublea,doubleb)
{return(a+b);}
}
当在程序中使用时,会根据实参数据类型自动选择调用。
Operatep=newOperate();
Console.WriteLine(p.Add(3,5));//返回15
Console.WriteLine(p.Add(1.03,3.25));//返回4.28
(3).静态方法
使用static关键字来修饰。
静态方法不需要类实例,直接使用“类名.方法名”格式调用。
在静态方法体内不能够直接使用非静态成员,也没有this引用,因为没有实例可以引用。
例如3-4:
publicclassOperate
{
publiclongAdd(longa,longb)
{return(a+b);}
publicdoubleAdd(doublea,doubleb)
{return(a+b);}
publicstaticvoidhi()//静态方法
{
Console.WriteLine(str);//可以访问静态成员
//Add(3,5);//不能访问实例成员
}
privatestaticstringstr="youusesstaticmethod";
}
publicclassTest
{
publicstaticvoidMain()
{
Operatedf=newOperate();
Operate.hi();
df.hi();//错误不能引用hi()
df.Add(3,4);
}
}
3.4参数传递
refout
params
数组传递值会改变
3.5属性成员
属性的建立要使用属性声明,语法如下:
[访问修饰符]类型名属性名//声明属性
{get//返回存储在私有变量中的属性值
{return字段;}
set//存储属性值到私有变量
{私有字段=value;}
}
可以说,属性是一种特殊的方法,但属性和方法也有不同之处,主要有:
属性不必使用圆括号,但方法一定使用圆括号。
属性不能制定参数,方法可以指定参数。
属性不能使用void类型,方法则可以使用void类型。
属性使用方法与变量相同。
例:
publicclasscheckval
{
staticvoidMain(string[]args)
{
Console.WriteLine(checkval.mytime);
checkval.mytime1="10:
2:
22";
Console.WriteLine("nowis"+checkval.mytime);
}
privatestaticstringp_time="00:
00:
00";//静态私有字段
publicstaticstringmytime//静态属性
{
get
{returnp_time;}
}
publicstaticstringmytime1//静态属性
{
set
{p_time=value;}
}
}
3.3.6this关键字
this引用的是当前实例。
this关键字是一个隐含引用,它隐含于每个类的成员函数中。
this关键字引用类的当前对象,成员通过this关键字可以知道自己属于哪一个实例。
静态函数没有this关键字。
基类.方法名调用基类同名方法
(3).如果需要调用基类中的同名方法,应该使用”base.方法名”来调用。
classCar
{
…
}
classTrashCar:
Car
{
…
}
Carcar=newTrashCar();
//某一类型的引用变量可以指向该类或者其子类的对象。
Objectobj=newCar();
obj=newTrashCar();
由于C#中System.Object类是所有类的祖先,所以可以用Object类型的引用指向所有类型的对象。
实现多态性的核心和实质:
使用基类的引用指向派生类的对象,当程序运行时,编译器会自动确定基类对象的实际运行时类型,并根据实际类型调用正确的方法。
重载和覆盖的区别
(1).重载的两个方法具有不同的参数,可以有不同返回值类型;
(2).覆盖的两个方法具有相同的参数,返回值类型必需相同。
publicdoubleget_dis()//计算两点间距离
{
returnMath.Sqrt
(Math.Pow((p2.x-p1.x),2)+Math.Pow((p2.y-p1.y),2));
}
抽象类的作用(抽象类与接口的区别)
抽象类与接口紧密相关。
然接口又比抽象类更抽象,这主要体现在它们的差别上:
1)类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承,从抽象类派生的类仍可实现接口,从而得出接口是用来解决多重继承问题的。
2)抽象类当中可以存在非抽象的方法,可接口不能且它里面的方法只是一个声明必须用public来修饰没有具体实现的方法。
3)抽象类中的成员变量可以被不同的修饰符来修饰,可接口中的成员变量默认的都是静态常量(staticfinal)。
4)这一点也是最重要的一点本质的一点"抽象类是对象的抽象,然接口是一种行为规范"。
不同之处:
1、定义
抽象类表示该类中可能已经有一些方法的具体定义,但是接口就仅仅只能定义各个方法的界面(方法名,参数列表,返回类型),并不关心具体细节。
1、用法
1)在继承抽象类时,必须覆盖该类中的每一个抽象方法,而每个已实现的方法必须和抽象类中指定的方法一样,接收相同数目和类型的参数,具有同样的返回值,这一点与接口相同。
2)当父类已有实际功能的方法时,该方法在子类中可以不必实现,直接引用的方法,子类也可以重写该父类的方法(继承的概念)。
3)而实现(implement)一个接口(interface)的时候,是一定要实现接口中所定义的所有方法,而不可遗漏任何一个。
4)另外,抽象类不能产生对象的,但可以由它的实现类来声明对象。
有鉴于此,在实现接口时,我们也常写一个抽象类,来实现接口中的某些子类所需的通用方法,接着在编写各个子类时,即可继承该抽象类来使用,省去在每个都要实现通用的方法的困扰
接口实现
接口引用只能调用实现的接口成员(不能实现接口内没有的成员)
实现:
类要继承某个接口用“:
”,在类的定义中给出接口中所定义方法的实际实现。
除显示实现接口外,类中接口实现必须显示声明为public。
publicinterfaceInterface1
{voidfun1(inti);}//基成员
publicinterfaceInterface2
{newvoidfun1(inti);//隐藏基成员
voidM1(inty);//添加新成员M1
}
publicclasscls1:
Interface1
{publicvoidfun1(inti){…..}}//实现接口方法
publicclasscls2:
Interface2
{publicvoidfun1(inti){…..}
publicvoidM1(inti){…….}
}
//要想显式使用方法,惟一的方法是将对象先转换为接口类型
voidIbook.read()//显式实现Ibook的read()
{Console.WriteLine("实现Ibook.read()方法");}
Ibookibk=clsasIbook;
if(ibk!
=null)
{
ibk.read();
}
属性
Message获取描述当前异常的消息。
Source获取或设置导致错误的应用程序或对象的名称(程序集的名称)。
TargetSite获取引发当前异常的方法。
StackTrace获取当前异常发生时调用堆栈上的帧的字符串表示形式。
引发I/O设备异常
try
{
//程序代码
}
catch(IOExceptionE)
{
//错误处理代码
}
可处理系统中的任何一种异常
try
{
//程序代码
}
catch(E)
{
//错误处理代码
}
throw可用来引发自定义异常“InvalidNumberInput”
if(grade<0&&grade>150)
{
thrownewInvalidNumberInput
(grade+“不是合法的成绩”);
}
try
{
//程序代码
}
catch
{
//错误处理代码
}
finally
{
//finally代码//无论有否异常该代码都会执行
}
catch(DivideByZeroExceptionex)//用0除异常处理
{
Console.WriteLine("ex.Message:
{0}",ex.Message);//尝试除以0
Console.WriteLine("ex.Source:
{0}",ex.Source);
Console.WriteLine("ex.TargetSite:
{0}",ex.TargetSite.ToString());
Console.WriteLine("ex.StackTrace:
{0}",ex.StackTrace);
}
catch(Exceptionex)
{
Console.WriteLine("General"+ex.Message);
}
接口类错误例:
usingSystem;
publicclassNoDescException:
ApplicationException
{
publicNoDescException(){}
publicNoDescException(stringmessage):
base(message){}
publicNoDescException(stringmessage,ExceptioninnerEx)
:
base(message,innerEx){}
}
publicinterfaceIFun1
{stringShowMe();}
publicinterfaceIFun2
{stringShowMe();}
classCircle:
IFun1
{
publicstringShowMe()
{return"Circle-IFun1";}
}
publicclassObjShowMe
{
publicstaticvoidShowMe(objectobj)
{
if(!
(objisIFun1&&objisIFun2))
{
thrownewNoDescException("Interfacenotimplementedfor"+obj.ToString());
}
}
}
publicclassMyApp
{
staticvoidMain()
{
CirclemyCir=newCircle();
try
{
ObjShowMe.ShowMe(myCir);
}
catch(NoDescExceptionex)
{
Console.WriteLine(ex.Message);
}
}
}
定制处理未处理异常
没有通用的方法适用于所有C#程序。
Windows窗体应用:
Applicatioin.ThreadException+=newThreadExceptionEventHandler(method);
Windows控制台应用:
Thread.GetDomain().UnhandledException+=newUnhandledExceptionEventHandler(method);