C#基础总结 .
类及成员
类是一组对象的属性和行为特征的抽象描述,对象是类的实例。
类是抽象的,对象是具体的。 抽象是有选择的忽略。
封装:使数据及方法结合;控制访问可见性。
允许控制---只能通过公共的方法来访问对象。 允许变化---私有对象的类型发生变化也不会影响对象的使用。
静态数据描述了一个类的所有对象的信息。
静态方法只能访问静态数据,通过类来访问而不是对象。方法是公共的,数据是私有的。
声明一个类的对象并不会创建类的对象--使用new操作符创建对象。然后用对象.方法来处理数据。 this关键字指向当前对象(当前类的)---当不同作用域中的名称标识冲突时特别有用。
class BankAccout
{
.....public void SetName (string name)
{
this.name(指的是私有字段的) = name;
}
private string name;
}
访问修饰符:public 只要知道所在的命名空间就可进行访问private 只对所在的类或结构可见。
常量:是一个表示恒定不变的数值的符号。
字段: 表示一个数据的值,它或是只读的,或是读写的可分为静态字段和实例字段。初始化是可选的,初始化的值必须在编译时可以确定下来,结构的字段值不能被初始化。只读字段必须声明或在构造函数中进行初始化,不一定在编译时就要确定下来,值不能改变。
方法:是一个函数,用来改变或查询一个类型(静态方法)获知一个对象(实例方法)的状态。方法一般需要读写类型或对象的字段。静态方法只能访问静态数据(字段)
构造函数及析构函数
构造函数首先是一个方法。
1.分配内存:使用new关键字从托管堆中分配内存
2.初始化对象的附加成员(方法表指针及内部保留字段)
3.使用构造器初始化对象-使用类的名字后跟括号。
CLR要求每个类至少定义一个构造函数。(没有的话,编译器会自动创建缺省的构造函数)缺省的构造函数的特点:pubic 访问级别;与类同名;没有返回类型(包括void);无参数;将所有的字段初始化为0,FaLSE,null。
构造函数可以被重载(同作用域,同名称,不同参数;可实现用不同的方式对对象进行初始化,可有不同的访问限制)重载的构造函数可能包含重复的代码。
结构的构造函数:编译器总是生成一个缺省的构造函数,缺省的构造函数将所有的字段初始化为0。结构中声明的构造函数不会自动将字段初始化为0,必须对所有的字段进行初始化,不能声明缺省的构造函数,不能将声明访问修饰符为proctecd的函数。
私有的构造函数可以组织对象的创建,不允许用new来实例化新的实例,静态的方法不需要实例化类就可以使用此方法用类.静态方法调用。
静态构造函数用于初始化类型的静态字段。(不能包含访问修饰符;必须是无参的;默认情况下,没有静态构造函数,定义的话也只能有一个静态构造函数;内联的初始化会自动生成构造函数。)不支持静态构造函数的重载。
静态构造函数的访问限制私有,其调用由CLR负责。对象生命期创建对象:使用new关键字来分配内存;使用构造函数在所分配的内存中初始化对象。使用对象:调用对象的方法。销毁对象:内存被回收。
局部变量---在方法中定义的变量析构函数是用于实现对象清理的机制。
方法及参数调用方法在同一个类中调用此方法--使用方法的名字后跟参数列表及括号。调用其他类中定义的方法--必须同时指定包含此方法的类;被调用的方法必须声明了相应的访问修饰符如public。
嵌套调用--可以在方法中调用其他的方法。
局部变量:当方法开始执行时创建,对方法来说是私有的,退出方法是被销毁。
共享变量:在类级别定义的变量时共享变量,可以被多个方法同时访问。
作用域冲突:当局部变量与共享变量存在命名冲突时,编译器不会警告。优先使方法内的局部变量用共享变量时要用this指定。声明及调用参数:声明参数--将参数放在方法名后的括号内;为每一个参数定义参数名及类型。调用参数的方法--为每一个参数指定值。传递参数值类型按值传递--传递给方法的将是值类型实例的一个拷贝,调用方法中的实例不会受到影响。
引用类型俺值传递--参数的传递时通过传递指向对象的引用来完成的,引用(指针)本身是按值传递的;方法可以改变引用对象。
引用参数:对参数内存地址的引用。使用引用参数:在方法中声明及调用时使用ref关键字;
变量的值及类型必须匹配;在方法内对参数所做的改变会影响到调用者;在调用方法之前必须指定参数的值。
输出参数:参数值并不传递到方法内,用于向方法外而不是方法内传递的值,不要求必须有初始值out变长参数:使用params关键字,在参数列表的最后声明,声明一维数组,编译时进行匹配检查,总是按值传递。
eg:static long AddList(params long[] v)
{
long total ,i;
for(i=0,total =0;i<v.Length;i++)
total+=v[i];
return total;
}
static void Main()
{
long x = AddList(63,21,84);//此地方可以继续加参数只要别超过long型。
}
递归方法:方法对自己进行调用
eg:
public int factorial(int n)
{
if(n<=1)
return 1;
else
return factorial(n-1)*n;
}
方法及运算符重载
方法重载:在同一个类中具有相同名称的方法。通过参数列表进行区分;
方法签名:在一个类中,方法的签名必须是唯一的,如方法的名称,参数类型,参数个数,参数顺序,参数的修饰符。
对签名没有影响:参数的名称,方法的返回类型,是否使用params,不能仅存在ref及out的差别。使用重载方法:条件:需要具有不同参数的类似的方法;要在现有的代码上添加新的功能。不要滥用重载(调试,维护较困难)
操作符的重载(构造函数的重载)
eg:
class Vector
{
public double x,y,z;
public Vector(double x,double y,double z)
{//初始化类中的三个字段
this.x=x; this.y=y; this.z=z;
}
public Vector(Vector rhs)
{//构造函数的重载,将类的值赋给参数rhs
x=rhs.x; y=rhs.y; z=rhs.z;
}
public override string ToString()
{
return"("+x+","+y+","+z+")";
}
public static Vector operator +(Vector lhs, vertor rhs)//操作符的重载运算符返回Vector类型
{//其参数的类型要与运算符的返回类型相同。
Vector result = new Vector(lhs);
result.x+=rhs.x;
result.y+=rhs.y;
result.z+=rhs.z;
return result;
}
static void Main()
{
Vector vect1,vect2,vect3;
vect1 = new Vector(3.0,3.0,1.0);//实例化并初始值
vect2 = new Vector(2.0,-4.0,-4.0);
vect3 = vect1+vect2;//c#默认是不支持两个对象相加,但重载过的可以。
Console.WriteLine("vect1="+vect1.ToString());
Console.WriteLine("vect2="+vect2.ToString());
Console.WriteLine("vect3="+vect3.ToString());
Console.ReadLine();
}
转换操作符方法必须是public及static的。显示转换用explicit关键字隐士转换用implicit关键字
属性及索引器
属性是一种(封装)内部信息的有效方法,保护了类内部的字段。简洁的使用方法,灵活性,允许更改前验证数据,可以透明的公开类中的数据,当数据被更改时,可以采取行动,如引发事件。
属性提供了类似于字段的访问:使用get访问器方法提供读取访问,使用set访问器方法提供设置访问。
eg:
class Button
{
public string Caption//Property,通过属性方法访问私有字段,
//Caption属性封装了下面caption私有字段
{
get{return caption;}
set{caption=value;}
}
private string caption;//Field 私有字段
}//使用属性
Btton button = new Button();button.Cation = "Button";//为属性赋值
属性,字段区别:属性是逻辑字段--get访问器方法可返回一个经过计算的值。
相似性:使用的语法类似的。不同:属性不是值,他们没有地址(本质上是操作字段,对字段进行封装)属性不能被当做方法的ref及out参数来传递。
属性与方法区别:相似性--均包含要执行的代码,均可用于隐藏实现的细节,均可被添加virtul,abstract,override等修饰符。不同---句法:属性不使用括号,语义:属性的返回值不能为空,也不能使用任意多的参数。静态属性属于类,只能访问静态数据。属性的访问修饰符:
如:将get访问器方法声明为public,将set访问器方法声明为protected(此时只能在类的内部或者派生类内部赋值)索引器:可以看做是智能的数组。索引器提供了针对于对象的类似于数组的访问方式--当属性可以具有多个值的时候非常有用。
eg:
class Sample
{
public int this [int i]//this是索引器名称 int是索引器数值或给他赋值的值的类型。
{
get{return this.data[i];
}//返回数组data第i个坐标
set{this.data[i] = value;}//将value值赋到data字段里
}
private int data[] = new int[10];//Field 私有的整型数组
}//使用索引器
Sample mySample = new Sample();mySample[0]=1;//0传递给this [int i]中的i中然后索引器再把1赋值给data数组中...
int a = mySample [2];//会调用get访问索引器及数组的区别相似:均使用数组语法不同:索引器可以使用非整形下标,(索引器可以被重载,可以同时定义几个使用不同索引类型的索引器,)它不是变量,没有实际的存储位置,不呢个将索引器作为ref和out参数传递
索引器与属性的区别
相同:都使用get及set访问器方法,都没有地址,返回类型都不能为空不同:索引器可以重载,索引器不能是静态的定义索引器时,需要制定至少一个索引参数,针对每一个参数均需指定一个值,不能使用ref及out参数修饰符。
委托及事件
委托:当把方法传递给其他方法时使用。一个方法需要对另一个方法进行操作,此时需要将第二个方法作为参数传递到第一个方法中。
使用委托--定义要使用的委托,即告诉编译器这种委托类型代表了哪种类型的方法,然后创建该委托的一个或多个实例。声明委托就是定义了一个类型,此类型封装了一个有着特定参数集合即返回值的方法的定义。
delegate void MyDelegate1(string s);//为一个方法声明了一个委托,此方法接受一个string类型的参数,且返回值为空。委托相当于定义了一个新类,在定义类的任何地方都可以定义委托。实例化委托:使用new操作符创建委托对象。委托的构造函数总是带有一个参数,此参数就是委托的引用的方法。
eg:将委托实例化为
(instantiating)MyClass类中的静态方法
HelloMyDelegate1 a=new MyDelegate1(MyClass.Hello)//将委托实例化为MyClass类的对象p中的实例方法
AMethod MyClass P=new MyClass();
MyDelegate1 b = new MyDelegate1(p.AMethod);
调用委托//根据前面的声明及实例化过程,下面的语句调用了MyClass类中的静态方法Hello,使用了参数Worlda("World");委托的特征委托的实例可以是任何类型的任何对象上的实例方法或静态方法,只要方法的特征匹配与委托的特征即可。
多播委托:委托可以包括多个方法,调用时就可以按顺序连续调用多个方法,委托的签名必须返回voidMyDelegate a,b,c,d;a= new MyDelegate(Foo);b= new MyDelegate(Bar);c = a+b;//a和b联合成c委托,c是多播委托d = c-a;//把a委托从c中减去,则d委托只引用b委托Bar方法a+=b;//a是多播委托a-=b;//a又变成了单播委托
事件--对象间的通信介质,在.net中使用委托来对事件进行封装处理。声明事件的委托类型。加上event关键字还得加上委托
eg:
public delegate void MouseClicedEventHandler();
public class Mouse
{
public static event MouseClickedEventHandler MouseClicked;
(MouseClicked是事件的名称) ....}注册到事件:通过+=(Combine)注册到事件,通过-=(Remove)取消注册到事件。
private void MouseClicked(){..}//构造函数
Mouse.MouseClicked+=new MouseClickedEventHandler(MouseClicked//构造函数方法);
mouse.MouseClicked-=new MouseClickedEventHandler(MouseClicked);
触发事件:检查是否有注册到这个事件上的客户端(如果代表事件的字段为空,表示没有客户端),通过调用事件的委托来触发事件。
if(MouseClicked!=null)MouseClicked();
此时触发事件,通过调用事件的委托来处理事件何时使用委托,事件使用委托:当你需要c风格的函数指针;需要处理单一回调;回调时在方法调用或构造期间指定的,而不是通过add方法。使用事件:客户通过add方法对回调函数进行注册;可能会有多个对对象对事件感兴趣;希望最终用户可以容易的在设计器中添加对事件的监听。
继承派生类:从基类继承了字段及方法,可以添加自己的字段及方法。派生类以基类为基础创建避免代码的重复
class Person
{
string name;
int age;
public void Birthday()
{age++;}
}
class student :Person
{ int id;}
class Employee:Person
{ double salary;}
class Gradute:Student
{ string advisor;}
派生类的对象可以使用基类中的功能。
Student s = new Student()s.Birthday();
派生类只能有一个基类,不允许多继承。派生类可以访问基类中访问级别为protected的成员,其他类不可以。派生类的方法可以使用base关键字调用基类的方法。
class Person
{
public void Print()
{
Console.WriteLine(name);
Console.WriteLine(age);
}....}
class Student:Person
{
public new void Print()
{ base.Print();//
Console.WriteLine(id);
}...在派生类类中有与基类中的方法同名,有要调用基类中的方法此时base。
构造函数及继承创建一个派生类的对象应对整个对象均进行初始化--首先是基类的部分,然后是派生类的部分。
派生类的构造函数应该调用基类的构造函数--在构造函数体之前使用:base()的语法;
--基类的
class Person
{
public Person(string name,int age)
{...}
...}
class Student:Person
{
int id;
public Student(string name,int age,int id):base(name,age)调用基类里的构造函数并传递两个参数,只有这样才能初始化基类中的字段。
{this.id =id;}
}
当基类构造函数为默认时可以不加base()。
定义虚方法派生类有时需要重写基类的方法此时基类中的方法应定义为虚方法,使用virtual进行声明。
class Token
{
public virtual string Name(){..}
}
派生类重写里的方法必须与基类里的严格约束。
重写使用override关键字。
class CommenToken:Token
{public override string Name(){}}
可以继续对override方法进行重写;
不能呢个讲override方法声明为static或private;
override方法不能更改virtual方法的访问属性。
隐藏继承的成员:使用new关键字表示特意的隐藏可以隐藏虚方法及非虚方法。
class Person
{
int id;
public void SetId(int id)
{this.id = id;}
}
clss Student:Person
{
int id;
public new void SetId(int id)
{this.id =id;}
}
密封类不能作为基类,无法从密封类中派生(sealed)
抽象类abstract抽象类不能被实例化,但仍可使用其引用。包含抽象方法的类必须是抽象的。
多态
通过继承,一个类可以用作多种类型:可以用作它自己的类型,任何基类型,或者在实现接口时用作任何接口类型。这称为多态。
基类的引用可以指向派生的对象
class Person
{
public string name;
public int age;...
}
class Employee:Person
{
public double salary;..
}
Employee e = new Employee();
Person p =new Employee();基类的引用可以指向派生的对象is-a 类型兼容。引用的类型决定了允许的访问--通过基类的引用只能访问基类的成员。
Person p = new Employee();
p.name = "Bob";p.age = 23;p.salary = 42000.00//此时是不对的可以将派生类型的对象传递给基类引用的参数。
bool CheckAge(Person p)
{ return p.age>=21;}
有时候在继承层次中会出现相同的方法--每个类可以提供各自独立的版本,派生类中同名的方法可以隐藏掉基类中同名的方法,此时引用派生类中的方法。绑定:可以通过基类的引用调用方法。必须确定调用的是基类或是派生类的版本;确定的过程叫绑定。
void Evaluate(Employee e)//传递基类的参数
{ e.Promote();//基类中的同名方法}
Faculty f= new Faculty();//派生类实例化
Staff s = new Staff();
Evaluate(f);Evaluate(s);
静态绑定:用了基类的方法。
动态绑定:virtual , override要看调用的参数是基类的还是派生类的,如果是基类的就调用基类的反之亦然。通过基类的引用只能访问基类的成员,即使引用的是派生类的对象。使用new关键字
--派生类中的方法是隐藏了基类的方法;
--运行时方法的确定采用静态绑定的方法;
--根据引用变量的类型确定使用的方法。
使用override关键字
--派生类中的方法是重写了基类中的方法;
--运行时方法的确定采用动态绑定的方法;
--根据对象的类型确定使用的方法。
接口接口定义了一个规范也叫契约。使用关键字interface来创建接口。
接口可以包含方法,索引器,属性,事件。但不允许包含实现,不允许包含其它类型的成员。
interface IMyInterface
{
void Process(int arg1,double arg2);
float this [int index]{get;set;}
string Name{get;set;}
event MouseEventHandler Mouse;
}
接口的成员的缺省的访问级别为public不需要加public。类可以支持接口--声明class:interface,必须实现接口的所有成员
(就是在类中必须有接口中成员方法的方法体的实现)。
若要实现接口成员,类中的对应成员必须是公共的,非静态的,并且与接口成员具有相同的名称和签名;实现的方法可以是虚的或非虚的;
类的属性和索引器可以为接口上定义的属性或索引器定义的额外的访问器。接口引用可以指向实现接口的对象,访问限制,只能访问接口中定义的成员(接口和抽象类都不能实例化)IFigter f = new Soldier();多个类可以实现同一个接口,可采用各自不同的方法实现接口。通过接口来编写某个方法--此方法可以用于任何实现了接口的对象。类可以同时实现多个接口--通过逗号分隔,必须定义所有接口的方法。实现派生接口的类必须实现所有的方法--接口继承层次上所有接口定义的方法。(类中要给出接口中所有成员的具体实现)。
字符串ToString重写
ToStringpublic class Person
{
string name;
int age;
public override String ToString()
{
return String.Concat(name,":"age.ToString());}
}
例子:
public class UserInfo
{
private string uName;
private int uAge;
pulic string UserName
{ get{return uName;} }
public int UserAge
{ get{return uAge;} }
public UserInfo(string umae,int uAge)
{ this.uName = uName; this.uAge=uAge;}
public override string ToString()
{
return string.Concat(uName,":",uAge);//return "你调用了我自己的ToString方法!"}
}
class Program
{
static void Main()
{
userInfo u = new UserInfo("Wangli",40):u.ToString();
Console.WriteLine(u.ToString());
}
数值类型格式化字符串:
C表示货币格式D表示十进制格式E表示科学计数法F表示定点格式P表示百分比格式X表示十六进制格式
DateTime.Now.DayOfWeek.Tostring("D")//返回枚举类型
Console.WriteLine(DateTime.Now.Tostring());
复合格式化复合格式化支持构造的字符串包含多个经过格式化的对象;
支持复合格式化的方法:String的静态方法
Format,Consol.WriteLine,TextWrite.WriteLine(将输出字符串写到流或文件)
复合格式化:索引复合格式化中的格式字符串使用大括号中的数字标识可替换的参数
eg:
String MyString = String.Format("On{0},{2}yerars old.",Datetime.Now,"Tom",35);
Console.WriteLine(MyString);
复合格式化:格式可以在大括号中添加格式信息,来对最终的格式化输出添加更多的控制:调用的时替换参数的类型实现的IFormattable接口中的ToString方法;如果未实现此接口则调用无参的ToString方法。
parseeg:
1.
string sNum = "58";
int iNum = int.Parse(sNum);
Console.WriteLine(iNum);
2.
推荐使用string sNum="58";int iNum;if((int.TryParse(sNum,out iNum)){
Console.WriteLine(iNum);}else{ Console.WriteLine("不是数字!!!");
}
字符串基础
String 类为方便使用,C#提供了string关键字作为System.String的同义词。String 是引用类型--使用new关键字创建。可将字符常量自动转化为string对象(不用new)。
转义序列:使用转义字符/。
可以创建不进行转义的字符常量:字符串前加@string path=@”C:/windows/Config“;
String提供了只读的Length属性string s= "hello";
int i=s.Length;
String类型提供了只读的索引器索引从零开始,文档中对应的是chars数学,使用时应按照索引器的语法string s="hello";char c = s[4];s.ToUpper();
排序及反转可以通过ToCharArray方法将字符串的字符复制到字符数组中;
通过Array类中的Sort及Reverse方法可对其进行排序及反序。字符串不变性没有方法可以改变字符串的内容,实际上是创建了代表新值的新的对象。StringBuilder代表了可变的字符序列。提供了改变其内容的方法。允许用户对容量进行设置。
stringBuilder text=new stringBulider();
text.Append("dfd")text.Append()return text.ToString();
eg:
static void Main(string)
{
stringBulider text=new stringbulider();
for(int i=0;i<100;i++)
{
text.Append("字符"+i.ToString());
text.AppendFormat("{0}",i.TOstring());//
text.append(string.format("{0}",i.Tostring);
}
string Result=text.Tostring();}
}
正则表达式
Regex类创建正则表达式Regex方法--IsMatch方法,Replace方法模式匹配正则表达式的强大不是体现在特定字符的匹配上,而是在字符类型的模式匹配上