您的位置:首页 > 编程语言 > C#

C#简单总结

2010-08-01 12:11 162 查看
C#中语句包括选择语句、循环语句、跳转语句、异常处理语句等;其中选择语句包括if/else、switch/case;if/else语句由于两项选择,if后面跟的是判断语句(TrueORFalse);switch/case语句用于多项选择中,switch后跟一变量,在case中寻找和该变量输入相同的case语句,然后运行该case语句中的代码;最后break,跳出switch;注意case最后跟个defalut语句,意即如果case都不满足,则执行它中的语句,它的跳出语句可为break、也可为continue;
循环语句包括for、foreach、while、do/while;for语句的for后跟三条语句:局部变量的声明、循环的条件、变量的累加或累减;for和foreach语句常由于对数组或集合中元素的遍历;嵌套的for循环语句还可用于对多维数组或交错数组中元素的遍历;foreach语句的本质是for语句的嵌套来实现的,故其比for语句的执行效率低,但因foreach后的循环条件要求简单和var(匿名类型)的引入,使得foreach语句的使用比较方便灵活,因而使用频率也很高;while语句的while后跟一条件,满足条件则执行花括号中的语句,while语句通畅又来进行执行需要循环很多次、一般是进行死循环的代码段,它和多线程结合来使用;(因为跳出死循环需要用到线程);
do/while语句时不论while后的条件是否成立,它都会被执行一次;个人感觉它的使用不如前三种循环频繁;
跳转语句包括return、break、continue、goto;return语句通常用在需要返回结果的方法中,作用:跳出所在方法体;break:它主要出现在switch/case语句中(此时是跳出switch语句的作用),但在循环体中也经常使用;作用:跳出所在循环体,继续向下执行;continue:主要用在循环体中,switch/case语句也可以使用;作用:跳出其所在的循环体,被继续该循环体下次执行;注:在switch/case语句中时,switch/case语句并不是循环体;
异常处理语句包括try/catch、try/catch.../finally、try/finally;异常的处理对实际的业务很重要,一般每个业务都需自带义一个异常类;try语句块就像一个猎人,它是用来对可疑代码惊醒捕获,但抓到后,它会throw该异常所对应得异常类型,然后再catch块中进行寻找,满足该异常类型的catch块将会被执行,而finallly则是不管是否有catch块,其都会被执行,其实际业务中意义不大,但在授课时可以使用;个人感觉此知识点很重要;因为实际业务的硬性需求;
还有checked、unchecked语句,不常用(此处讲解略);
结构
结构是用关键字struct来声明的,其前面可以有访问修饰符,它可以继承接口,但它不可以继承结构,个人感觉应该是因为他是值类型的原因吧,结构是一种类型,它和类、接口、委托都是一个级别的;因其不可继承接口,故其成员不能有protected关键字;接口的实例化可以不使用new关键字,如果为结构定义构造函数则其构造函数必须含有参数;
枚举
枚举是一种值类型,它是用enum关键字来声明的,它有访问修饰符;它一般用在其值可以确定的一些数据类型的定义,且默认的索引标记是int类型(也可为其他类型),默认的分配为从零开始,然后累加且索引可以重复;
值类型、引用类型
数据类型分为值类型和引用类型;值类型的数据的存储时在线程堆栈中,而引用类型的数据的地址(可以视为一指针)是存储在线程堆栈中,而其数据的存储是在委托堆里面;它们之间的区别造成了变量来回赋值时结果的不同;
例如如下代码:
int i = 1;
int a = i;
a++;
Console.WriteLine(i);
Console.WriteLine(a);
//输出答案为:1 、2
Console.WriteLine("==================");
int[] o = new int[] {1};
int[] m = o;
m[0] = 2;
Console.WriteLine(o[0]);
Console.WriteLine(m[0]);
//输出答案为:2 、2
该例子很好的说明类值类型和应用类型的区别:值类型在赋值时是将数据的一副本赋值过去,题中a的修改对i不影响;而应用类型的赋值是将地址赋过去;题中m[0]的修改是将托管堆中的数据修改,该空间也指向o[0],故o[0]也发生了改变;
谈到值类型和引用类型,我们便很用必要说说装箱和取消装箱(可理解为拆箱),它指的是值类型和引用类型之间的类型转换;
int i = 12;
Console.WriteLine("{0} {1}",i,i.GetType());
string o = Convert.ToString(i);//装箱
Console.WriteLine("{0} {1}", o, o.GetType());
int n = Convert.ToInt32(o) ;//拆箱
Console.WriteLine("{0} {1}",n,n.GetType());
输出的结构为:12 System.Int32
12 System.string
12 System.Int32
由结果可以开出,int类型的i的类型发生了转换,其值没变,装箱其实就是 将值类型的变量转换为引用类型的变量;这个过程需要为新转换的引用类型对象在托管堆中开辟内存空间;反之叫拆箱,将引用类型的变量重新转换为值类型也需要大量的计算;如果我们还是对一集合中的所有元素进行装箱和拆箱,那么大家可以设想下?没错,它会耗费我们大量的空间资源,严重影响程序的性能;所以我们在编写代码的过程中应当尽可能的避免装箱和拆箱;
值类型主要包括的有:int、double、float、decimal、struct、enum、char;
引用类型主要包括有:string、class、array、collection(hashtable、arraylist、stack、queue);
其中注意:值类型的初始化和赋值一样;而引用类型的初始化则必须通过new关键字来进行,当然也有例外的;例如:string的初始化的代码表现形式就和值类型的一样;而array的声明需要用CreateInstance()方法;
string和stringbulider
对于string大家都不陌生,它可以说是应用最广泛和频率最高的系统类型之一string是一个类型;它是Unicode字符的有序集合,用于表示字符串(可视为是char[]数组),作为引用类型的它初始化的形式和值类型一样(感觉应该是为了操作简便);它的主要方法有:contains(string s1)(使用该方法的字符串实例是否包含s1)、indexof(string s1)(将实例中与是所匹配的第一个字符的索引值返回)、compare(比较两个字符串)、copy(创建一个与指定的string相同的字符串实例)、toupper(将字符串全部转换为大写)、tolower(将字符串全部转换为小写)、split(condition)(根据condition将字符串分割为字符串数组)、length(获取字符串的长度);
需要注意的是:string和值类型之间的转换不可以用数值之前加(Type)的形式;需要用ConvertTo方法或Parse方法;
对于stringbulider:
表示可变字符字符串;(个人不太应用,感兴趣的同学可以在MSDN上搜索StringBuilder);
数组
数组可以认为是具有相同类型的数据的长度固定的集合;
数组是引用类型,其可以分为一维数组,二维数组、多维数组和交错数组(也叫数组的数组);
数组的初始化有三种:如下:
int[] a = { 1,2,3,4};//直接赋值
int[] b = new int[4];//确定了数组的长度,再分别为各元素赋值
b[0] = 1;
b[1] = 2;
b[2] = 3;
b[3] = 4;

int[] c = new int[] { 1, 2, 3, 4 };//介于第一种和第二种之间,它的大小已经确定
要知道的是:数组一旦被实例化(初始化),它的长度变已经确定下来了,不可以再增加或者是删除元素了;这点其实是数组的一个缺陷;而集合中ArrayList弥补这一缺陷;
集合
集合包括hashtable(哈希表)、arraylist(变长数组)、stack(堆栈)、queue(队列)
集合中在编程当中最常有的是arraylist,因为存储多个相同类型或相似类型数据(泛型的产生)以及存储数据个数的不确定性这样的情况在现实业务中很普遍,所以造成了arraylist的引用频繁,尤其是泛型产生后,可以将类型定义为一个参数,这就造成了泛型arraylist应用更加广泛;hashtable是表示键/值对的集合,这些键/值对根据键的哈希代码进行组织;这有点像我们考试试做选择题时的题号和对应的答案;没错,假如我们要做一个学生考试系统的话,那么就需要定义Directory(存储键/值对)类型的变量的集合来存储学生所做的选择题答案集;
stack的特征是先进后出;
queue的特征是先进先出;
两者的具有应用个人暂无,此处先不作介绍;


类是一个很重要的概念;类应该是面向对象的思想产生后而逐步形成的,面向对象的编程语言的产生打破了面向过程编程语言的那种思维模式,使得代码的编写更加容易,更加简单,更加高效,更加符合人的思维;类就是类型,它是具有相同数据类型和相似行为特征的一组对象实例集合的抽象模型;万事万物皆对象,世界上没有什么不是对象,我们可以经过观察思考,把那些特征相似和功能相似的对象抽象为一个类,而那些特征和功能叫做这个类的成员;以car类为例:汽车的颜色,名字,重量,高度,宽度等等便叫做该了类的字段(即字段又来存放具体的数据),而这个汽车的说明书上对这些字段的描述的信息我们可以称为属性(你也许并没有看见car实体,但你通过说明书却知道了这些字段),也就是说属性用来封装字段;而汽车能跑,能响铃,会加速、刹车等具体的功能我们便将它称为类的(普通)方法;类的成员还可以包括索引器,委托,事件;但最重要的还是上面说提到的字段、属性和方法以及下面所讲到的构造函数;
类的访问修饰符包括:
位于命名空间中的类可用:
public:成员可以被任何其他类访问;
internal:成员可以被在同一程序集其他类访问;
不能是用protected、private、internal protected;
而出于类内的类可以使用:private和internal protected
方法参数
方法可以分为有参方法和无参方法,例如:当创建一个类后,如果我们不定义构造函数,系统会默认的产生一个无参的构造函数,或者我们自定义的无参构造函数,还有就是程序入口函数Main方法也可以是无参的;对于普通的方法来说,一般它们都要带有参数,因为它们需要实现一些具体的功能,需要接收一些数据,处理然后得出一定的结果;方法中的参数变量一般都是形式参数,而且是局部参数,它们作为一个标记来接收与它类型相同的传递过来的实参;然后还需知道的就是在方法中的声明变量称为局部变量,它们的生命周期为:伴随着方法的执行而产生,伴随着方法的执行结束而消亡;
说到方法,此处我们有必要说说在类继承关系中同种类型、相同名称的方法的调用情况;
class Father
{
internal void Method()
{
Console.WriteLine("我是Father的Method");
}
}
class Son : Father
{
//public void Method()
//{
// Console.WriteLine("我是Son的Mthod");
//}
}
static void Main()
{
Son s = new Son();
s.Method();
}
显示结果为:我是Father的Method;
由此可以知道:如果Son类中没有Mthod,则其会向其父类中寻找,如果找到,则调用父类的Method方法;如果其含有Method,则调用自身的Method方法;
分部方法、扩展方法、匿名方法
方法还可以分为:分部方法、扩展方法、匿名方法;
对于分部方法,它使用关键字partical来进行声明,分部方法必须处于分部类中,而分部类则必须处于同一个命名空间中;分部类前可以添加访问修饰符;而分部方法前则不能添加访问修饰符和 virtual、abstract、override、new、sealed或extern;分部方法的默认访问范围为private、因此分部方法的调用必须位于分部类内部;且分部方法的签名和方法的实现需各位于一个单独的分部类中;
扩展方法是使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式、修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用;
匿名方法:顾名思义,匿名方法就是没有方法名的方法,匿名方法使你能够省略参数列表,这就意味着可以将匿名方法转换为带各种签名的委托;

构造函数
每个定义的类型都必须包含构造函数,即使你不去显示地声明,系统也会自动的为该类声明一个默认的无参构造函数,当然如果你声明了构造函数,则所声明的构造函数会自动替代系统默认的构造函数,构造函数可以定义一个或多个,构造函数可以带参数(一个或多个),也可以不带参数;构造函数的作用是去实例化(初始化)所在类型中的字段;当然字段的实例化(初始化)也可以用为其定义属性来完成,但对于大部分的引用类型的变量,因为引用变量的实例化(初始化)需要内存为其分配空间(即使用new关键字),故对于这类变量的实例化(初始化)通常都是在构造函数中完成;因为面向对象中有三大特性,此处我们需要了解下在类的继承关系中构造函数的一些情况;
代码如下:
class Father
{
public Father()
{
Console.WriteLine("我是Father构造函数");
}
}
class Son : Father
{

}
....
static void Main()
{
Son s = new Son();
}
运行的结果是:我是Father构造函数;
由此可以看出来子类中如果没有定义构造函数,则其后自动调用父类的构造函数;如果自己定义了构造函数,则其会先调用父类的构造函数,父类同样会调用其父类的构造函数,一级一级往下调用,直到调用到基类Object的构造函数;最后返回来再调用自己的构造函数;
字段、属性
字段和属性都是类的成员;字段可以有的访问修饰符有public、private、internal、protected;
其中字段是用来存储数据的;属性的修饰符只能是public(因为定义成其他的没啥意思);编译器在二次编译是其实没有属性这一概念的,属性其实是有两个访问器:get和set组成;它的作用是用来封装字段;字段的属性可以为只读、只写、可读写;还有的就是可以通过为类中个字段设置属性来实例化一个类对象(对于没有引用类型字段的类[string类型除外]);
索引器
索引器也是类的一个成员;它的语法结构体和属性很类似(都有get和set);索引器允许类或结构的实例就像数组一样进行索引。索引器类似于属性,不同之处在于它们的访问器采用参数;索引概述:
使用索引器可以用类似于数组的方式为对象建立索引;
get访问器返回值;set访问器分配值;
this关键字用于定义索引器;
value关键字用于定于由set索引器分配的值;
索引器不必根据整数值进行索引,由你决定如何定义特定的查找机制;
索引器可以被重载;
索引器可以有多个形参,例如当访问二维数组时;
委托
委托用delegate关键字来声明;委托是事件的基础;通过将委托与命名方法或匿名方法关联,可以实例化委托;为了与命名方法一起使用,委托必须用具有可接受签名的方法进行实例化;委托类似于C++中的函数指针;但是,委托是类型安全和可靠的;
事件
事件用event关键字来声明;类或对象可以通过向其他类或对象通知发生的相关事情;发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”;
事件具有以下特点:
发行者确定何时引发事件,订户确定执行何种操作来响应该事件;
一个时间可以由多个订户,一个订户可以处理来自多个发行者的多个事件;
没有订户的事件是永远不会被调用;
事件通常用于通知用户操作;
如果一个事件有多个用户,当引发该事件时,会同步调用多个事件处理程序;
可以利用事件同步线程;

静态类、密封类、抽象类
静态类和类成员用于创建无需创建类的实例就能够访问的数据和函数;静态成员可用于分离独立于任何对象标识的数据和行为;
主要功能:
它们仅包含静态成员;
它们不能被实例化;
它们是密封的、因此不可以被继承
它们不能包含实例构造函数;
静态类是前面带有static关键字;

密封类:它用关键字sealed来定义,密封类不能被继承;密封类不能用在基类;因此,它也不能是抽象类;密封类的主要用于防止派生,因密封类从不用作基类;所以有些运行时优化可以使对对密封类的调用略快;

抽象类是通过abstract关键字来声明的;抽象类不能被实例化,抽象类的用途是提供多个派生类可共享的基类公共定义;抽象中可以包括抽象方法,也可以包括实例方法;
接口
用interface关键字来声明;它只包含方法、委托、或事件或属性或索引器的签名(不包含字段);方法的实现是在实现接口的类中完成的;
一个接口可从一个或多个基接口继承;
实现接口的类可以显示实现该接口的成员;显示实现的成员不能通过类实例访问,而只能透过接口实例访问;

虚方法、重载方法
虚方法是用关键字virtual声明;调用虚方法时,将为重写成员检查该对象的运行时类型;将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员;默认情况下;
virtual修饰符不能与static、abstract、private或override修饰符一起使用;通过override来对虚方法进行实例化;
重载方法
方法的重载是对指方法的类型和名称相同,但其参数不同的方法,这样的方法集叫做方法重载;个人认为方法的重载多用于构造函数的重载;这样使得对一个类的实例化可以有多种方式;

继承
继承是面向对象的主要特性之一,它是指子类继承父类时,子类将继承父类的构造函数(不管子类对象实例化时的构造函数是不是带参数,父类的构造函数有没有参数,子类的对象实例化时这些构造函数都会被继承;并且这样的继承持续到基类object)和父类的非private成员;类的继承只能是单继承关系;
virtual方法可以有实现的;

多态
实现了一个类的多种形态,一般这个类指的就是父类型;子类使用new关键字可以把父类中与其内同名同类型的的某一方法给隐藏了;子类可以使用override把父类的virtual方法给覆盖掉;例如:
class Father
{
public virtual void Method()
{
Console.WriteLine("我是Father的Method");
}
}
class Son : Father
{
public override void Method()
{
Console.WriteLine("我是Son的Mthod");
}
}
static void Main()
{

Son s = new Son();
s.Method();
Father f = new Son();
f.Method();
}
显示的结果为:我是Son的Mthod
我是Son的Mthod
因为Son类使用override把Father类的Method方法覆盖;
而如果代码如下:
class Father
{
public void Method()
{
Console.WriteLine("我是Father的Method");
}
}
class Son : Father
{
public new void Method()
{
Console.WriteLine("我是Son的Mthod");
}
}
static void Main()
{
Son s = new Son();
s.Method();
Father f = new Son();
f.Method();
}
显示结果:我是Son的Mthod
我是Father的Method
因为Son类的Method方法没有使用override,故Father类型的对象f依旧调用了Father类的Method方法;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  职场 休闲 C#语法