第03篇:C#星夜拾遗之语法基础
了解C#的基本语法,这是学习一门语言的必经之路。这些基本语法包括:数据类型、运算符和表达式、流程控制、字符串、类和对象、结构和枚举、命名空间等。本文主要列举出来笔者觉得算得上基础知识的内容。对于本文中的一些内容的详细讲解,可以参照anytao的博文系列:你必须知道的.NET
特别说明:本文多为网上摘抄或者之前的笔记,存在一定的不连贯,读者可以根据自己的实际情况,在百度或者Bing中查找更好的文章。
数据类型
值类型和引用类型的区别:值类型存放在栈(heap)中,引用类型存放在堆(stock)中;对于引用类型来说,两个变量可以同时引用同一个对象,这样若对一个变量修改,就会影响另一个变量的值。而对于值类型来说,不会产生这样的结果。
内置类型:
内置类型包括:int,long,float,double,decimal,string,char,bool
说明:它们是通用类型系统(Common Type System)定义的基本类型。它们只需要声明和初始化后就可以使用。不需要用new运算符来实例化,因为他们在变量定义进入范围是在堆栈中分配,同样,当离开所在情景时,自动解除分配。
宽度窄的(即字节数少的)数据类型可以直接赋给较宽的数据类型,并会自动转换为新类型。例:float a =
引用类型:
Object类型:它是所有类型的基类。C#中所有的类都是直接或间接从object类型派生出来的。Object关键字其实是预定义的System.object类的别名,在程序中用object或System.object都具有一样的作用。
Class类型:它是一个类定义,包含数据成员(常量、字段和事件)和函数成员(方法、属性、索引、操作符、构造函数和析构函数)。类支持继承。
String类型:它是直接从object类派生的一个封装类。String类实例表示的是Unicode字符串。同样,string类型其实是预定义的System.String类的别名,在程序中使用string或System.String作用是一样的。
Interface接口类型:其实是一种大家需要共同遵守的协议。实现某种接口的类或结构必须遵守此协议。一个接口可以派生于多个基接口,同时,一个类或结构可以实现多个接口。
Array 数组类型:它也是一种数据结构,但必须利用索引才能访问其数据,即数组元素。数组中所有的元素都具有相同的类型,称之为数组元素类型。数组元素可以使任意类型包括数组类型。C#中的数组是从抽象类System.Array中派生的应用类型。
Delegate代理类型:它有两种情况,一种是引用对象的一个静态方法,另一种是引用一个对象的实例以及此对象的实例方法。其实它与C中的函数指针非常相似。但函数指针只能引用静态函数,而C#代理既可以引用静态的方法,也可以引用实例方法。
运算符
C# 运算符类型:
算术运算符号: +、-、*、/、%
逻辑运算符: &、|、~、^、!、&&、||、true、false
字符串连接运算符: +
自加、自减运算符:++、--
移位运算符:<<、>>
关系运算符:==、!=、<、>、<=、>=
赋值运算符:=、+=、-=、*=、/=、&=、|=、^=、<<=、>>=
成员访问运算符:.
下标运算符号:[ ]
强制类型转换运算符:( )
代理连接和移走运算符:+ -
对象运算符:new
类型信息运算符:is 、sizeof 、typeof
溢出异常控制运算符:checked 、unchecked
间接取地址运算符:*、->、[]、&
三元运算符号 int a = 10; string strRusult = (a > 17) ? "大于" : "小于"
运算符优先级和综合性
!NOT
*、/、%
+、-
<、<=、>、>=
==、!=
&& 、||
=
溢出说明:
对于整数运算溢出,如果有checked运算符指定,则抛出异常OverflowException,如果有unchecked运算符指定则丢弃最高位;
浮点算术运算发生溢出或0除时,不抛出异常;
小数算术运算发生溢出抛出OverflowException异常,如果0除,将抛出DevideByZeroException。
表达式
表达式是可以计算且结果为单个值、对象、方法或命名空间的代码片段。
表达式可以包含文本值、方法调用、运算符及其操作数,或简单名称。简单名称可以是变量、类型成员、方法参数、命名空间或类型的名称。
表达式可以使用运算符,而运算符又可以将其他表达式用作参数,或者使用方法调用,而方法调用的参数又可以是其他方法调用,因此表达式既可以非常简单,也可以非常复杂。如:int i = 5; string s = "Hello World";
下面是几种特殊的表达式:
成员访问表达式: E.I (E是名字空间或预定义的一个类型, I是可访问的成员名称)
元素访问表达式: P[A] (P是一个数组名称或一个类、结构和接口变量,A是一个下标访问参数)
this表达式:this表达式仅允许在一个类型的构造函数、实例方法或一个实例访问器中使用
base表达式:base访问表达式用于访问被当前类或者结构隐藏了的基类的成员。Base表达式允许在构造函数、实例方法或者实例访问器中使用。对于base.I形式,I必须是基类的一个成员;对于base[E],E必须是基类中存在的、可用的下标指示器。
new表达式:它为某类型创建一个实例。包括:创建对象新实例、创建数组新实例、代理创建实例
流程控制
选择控制语句
if语句:它有三种基本形式:单条选择, 如果/否则,以及多情形选择。关键词包括:if、else 、else if
switch语句:
1、语法结构:
switch (expression)
{
case label1 :
[statementlist1]
[break;]
[ ...
[ case labelN :
[statementlistN]
[break;] ] ]
[ default :
[statementlistDefault]]
}
2、使用switch语句遵循规则:
Switch表达式必须是以下类型中的一种: sbyte,byte,short,ushort, int,uint,long,ulong,char,string,或者enum类型,不能对任何其他类型使用switch语句。
case标号必须是常数表达式,如42或“
case标号不允许相同的值写两个case标号。如果想要对多个值执行相同的语句,必须为每个值重复case标号语法。没有简便的方法来组合一个case标号值。
在switch表达式后面是个switch 块, 当Switch表达式的值同某一个case后面的常量表达式的值相匹配时,就执行此case后面的语句,直到遇到"break"语句或者"goto"语句为止。每个分支以关键字"case"作为标号,其后为常量表达式,然后是分号(:)。
可以在所有的分支选择的后面加上一个"default"分支。如果没有匹配的常量表达式,就进入default分支,并执行该分支的语句。虽然default标号是可选的,我建议你加上该分支。这将有助于处理一些意外事件 ,使得你的程序能够捕捉和处理不可预见的事件,从而使得程序更加可靠。
每个"case"标号必须以"break"语句作为结束。"break"语句将使得程序退出switch语句,并从switch块后面的一条语句开始执行。
对于"default"标号来说,"break"语句是可选的,因为有"break"语句和没有"break"语句,其运行结果是一样的。
循环控制
循环控制语句主要包括:"while" 循环、"do" 循环、"for" 循环、"foreach"循环。
"while"循环语句
1、程序例
class Whileloop
{
public static void
{
int intI= 0;
while (intI < 10)
{
Console.Write("{0} ", intI);
intI ++;
}
Console.WriteLine();
}
}
2、说明:
上面是一个简单的while 循环例子。以关键字"while"开始,后面是个布尔表达式,(所有的控制语句都使用了布尔表达式)这就意味着表达式必须计算出true 或者false值。本例中,我们将检查intI变量,看看它是否小于10。 因为intI已经初始化为0,第一次计算时,该布尔表达式将返回true值。一旦布尔表达式的值为true,将执行该布尔表达式后面块中的语句。
在while块中,我们把数字和空格输出到控制台中,之后,对 intI进行加1运算。一旦执行了while块中的语句之后,再次计算布尔表达式的值,这种情况将一直循环下去,直到该布尔表达式的值为false为止。 一旦布尔表达式的值为false, 程序将从while 块之后的第一条语句开始执行。在本例中,我们把数字0到9输出到控制台中,之后退出while块,再输出一个新行到控制台。
"do"循环语句
1、程序例:
class Whileloop
{
public static void
{
int intI= 0;
do
{
Console.Write("{0} ", intI);
intI ++;
} while (intI <10)
Console.WriteLine();
}
}
2、说明:
"do" 循环的格式是: do { <语句> } while (<布尔表达式>);其中的语句可以是任何合法的C#语句,布尔表达式同以前的规定一样,其返回值要么为true,要么为false。
"do" 循环可以保证:循环体中的语句至少执行一次。与此相对应的是:"while" 循环一开始时,计算布尔表达式的值,"while" 循环不能保证循环体中的语句能够至少执行一次。
"for" 循环语句
1、 程序例
class Forloop
{
public static void
{
for (int i=0; i < 20; i++)
{
if (i == 10)
break; //跳出循环
if (i % 2 == 0)
continue; //不执行本次循环体以后的语句,继续新的循环
Console.Write("{0} ", i);
}
Console.WriteLine(); //只打印出1,3,5,7,9这五个数字
}
}
2、 说明:
当已经精确地知道循环的次数时, For 循环语句就派上了用场。"for" 循环中,括号中内容由三个由分号隔开的部分: "(<初始化表>; <布尔表达式>; <post-loop 动作表>)"组成。
初始化表是个由逗号隔开的表达式,在"for" 循环的整个周期中,这些表达式仅仅计算一次。计算是在一开始进行的,并且在循环语句的执行之前进行。
一旦进行初始化后, "for" 循环就进入第二部分:布尔表达式的计算。 这里的布尔表达式可以写得很复杂,但是结果只能是true或者false。布尔表达式通常用来验证计数器变量的状态。
一旦布尔表达式的值为true时,就会执行"for" 循环大括号中的语句。通常情况下,这些语句从左大括号开始,不中断地一直执行到右大括号。但在上面的程序例中有几个例外,几个"if"语句改变了程序的流程。
第一个"if"语句检查"i"是否等于10,这里使用了"break"语句,可在此处跳出循环,转入 "for"块后面的第一条语句的执行。
第二条"if"语句使用了求余运算符,看看"i"是否能够被2整除,如果余数等于0,就执行 "continue"语句。控制将跳过循环体中余下的语句,转入下一轮新的循环。你需要在块中正确地组织好语句,一旦满足有关条件,就执行相应的语句。
一旦程序流程遇到continue语句,或者遇到块的结尾处的右括号, 就转入"for" 循环括号中的第三项:post-loop 动作表,该表由逗号隔开,在"for"块中的语句都执行完毕之后,就执行该动作表中的动作。
"foreach"循环语句
1、 程序例
class ForEachloop
{
public static void
{
//定义一个数组
string[] names = {"Cheryl", "Joe", "Matt", "Robert"};
//打印出数组中所有元素
foreach (string person in names)
{
Console.WriteLine("{0} ", person);
}
}
}
2、 说明
"foreach" 循环列举出集合中所有的元素。上面程序例所使用的数组类型,就是这样的一个集合。(在"System.Collections"也可以由其他的数据类型作集合。). 在Main()方法中,我们所做的第一件事是:定义由四个字符串组成的数组names。
"foreach"括号中的表达式是由关键字in隔开的两个项组成。in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素。
该循环的运行过程如下:每一次循环时,从集合中取出一个新的元素值,放到只读变量中去,括号中的整个表达式返回值为true, "foreach"块中的语句就能够执行。一旦集合中的元素都已经被访问到,整个表达式的值为false,控制流程就转入到 "foreach" 块后面的第一条可执行语句。
其它控制语句
break:跳出循环
continue:结束本次循环,继续下一次循环
goto:跳转语句
retun:如果return 语句包围在带有finally块的一个或多个try块中,程序控制首先将被传递到最内层try块的finally块。如果程序控制已经达到一finally块的结束点,那么接下来,它将被传递到上一层try语句的finally块
throw:抛出一个异常
lock:它主要用于多线程间共享变量的同步处理。作用是对一个对象加上互斥锁。
using:C#的using语句包含一个或多个资源。一个资源就是实现了System.IDisposable接口的一个类或结构。它的处理过程是执行一条语句,然后释放该资源。在C#编译时,编译器会将using语句转换为三个部分:资源获取、资源使用、资源释放。资源的使用是包围一个带有finally语句的try语句。这个finally语句释放资源。如果获取资源的结果为null,那么finally语句中将不会调用Dispose方法,也不会抛出任何异常。
类和命名空间
结构和枚举
异常处理
数组、字符串
泛型、集合
………………
基础知识实在是太多了,如果你还没有学会,赶快装上MSDN,用到哪里查到哪里,这样即快速,又准确。