c#语法基础

一,概述

C#程序语言的语法,和.NET框架以及Mono完全兼容。和C/C++/Java相似。

二,语法基础

1,标识符Identifier

标识符是组成代码的元素,命名规范为:

命名规则:字母或_或@ + 字母或_或数字 (/用于转义,@用于逐个转义指定,@常用于保留关键字前以,字母为Unicode,大小写敏感)

具体命名规则:

  • ①除了上述_或@或/符号,不能包含空格、标点符号、运算符等其它符号。

  • ②C#为交互其它语言而允许以字符“@”作为标识符的开头,但它实际上在编译时会被忽略并非变量名的一部分,所以同时定义名为c和名为@c的两个字符变量会造成命名冲突。

  • ③标识符不能超过511个字

  • ④标识符不能与c#中的关键字Keyword或库函数名相同:C#只有不到 90 个关键字,分为上下文关键字(特定情况下才是关键字)和保留关键字。如果在其他语言写的要复用的代码中使用了C#的保留关键字一样的名称,为了在C#中保持与其他语言兼容,可以使用@于保留关键字前。

2,源文本literal

整数Integers

八进制octal

0365, 0[0..7]*

十六进制hexadecimal

0xF5, 0x[0..9, A..F, a..f]*

十进制decimal

245, [1..9][0..9]*

浮点数Floating-point values

单精度float

23.5F, 23.5f; 1.72E3F, 1.72E3f, 1.72e3F, 1.72e3f

双精度double

23.5, 23.5D, 23.5d; 1.72E3, 1.72E3D, …

字符源文本Character literals

字符char

'a', 'Z', '\u0231'

字符串源文本String literals

字符串String

“Hello, world”,”C:\\Windows\\”, @“C:\Windows\”

字符串中的转义字符

3,变量Variables

变量是和值有关联的标识符。

(1),命名规则:字母或_或@ + 字母或_或数字 (/用于转义,@用于逐个转义指定,@常用于保留关键字前以,字母为Unicode,大小写敏感)

(2),使用规则: 变量必须先定义(声明)后使用。

声明变量: 变量类型 变量名

变量赋值:变量 = 要赋的值

int MyInt//声明 MyInt = 35//初始化 int MyInt2 = 35 //声明 & 初始化 int a, b//多个相同类型的变量可以在同一行中一起声明 int a = 2, b = 3//多个相同类型的变量可以在同一行中一起声明和初始化|

C#变量被访问之前必须被初始化;否则编译时会报错。因此,不可能访问一个未初始化变量(如不确定的指针、超出数组边界的表达式)。变量在使用前最好习惯是要先声明和初始化。

(3)C#中没有全局的的变量或全局函数,全局方式的操作是通过静态函数和静态变量来实现的。

int i string text//在循环外未初始化 for (i = 0i<10I++) { text = "Line" + Convert.ToString(i) //在循环中未初始化,在退出循环的时候会丢失值,再引用就出错。 Console.WriteLine("{0},text); } Console.WriteLine("Last txet output in loop:{0},text) //出错。改正方法是在循环外初始化:string text="";

(4)命名约定:简单的用camelCase,复杂的用PascalCase

(5)变量的七种类型:

  • ①静态变量:带有“static”修饰符声明的变量称为静态变量,静态变量的初始值就是变量类型的默认值。存在期从类装载直到该程序结束。不用定义类的实例对象便可以直接存取静态变量

  • ②非静态变量(实例变量):不带有“static”修饰符声明的变量。存在期从从类实例创建到实例空间释放。非静态变量只有建立对象后,才能存取。

  • ③数组元素:每个数组元素的初始值是该数组元素类型的默认值,数组元素最好在初始时被赋值。

  • ④局部变量:指在一个独立的程序块,一个for语句、switch语句或者using语句中声明的变量,它只在范围中有效。

  • ⑤值参数:

  • ⑥引用参数:

  • ⑦输出参数:

using Systempublic classVariableInclude{public static string name="YourName" //定义了静态字符串变量public static int age=40 //定义了静态整型变量public string country="YourCountry" //定义非静态变量}public classVariableUse{public static void Main(){ Console.WriteLine(VariableInclude.name) //静态变量不用定义实例对象,可以直接调用 Console.WriteLine(VariableInclude.age)// Consloe.WriteLine(VariableInclude.country); 非静态变量不能直接调用,否则会出错   VariableInclude vi1=new VariableInclude() //定义类的对象后,才能调用非静态变量 Console.WriteLine(vi1.country) //}}public classOtherFormsOfVariable{/*v[0]是数组元素,a是值参数,b是引用参数,c是输出参数 */void F(int[] v,int a,ref int b,out int c){int i = 1//局部变量,不会被初始化 c = a + b++;//}}

4,常量

就是固定不可改变的值(量)

(1),静态常量:const声明的常量叫静态常量,必须声明时就初始化,且只能用常数值初始化 常量就是其值固定不变的量。可以作为一个字段属性或一个本地变量。常量是隐式静态的。

常量的声明和赋值格式(常量声明必须同时赋值):属性修饰符 + CONST + 类型声明 + 常量名 = 常量值

属性修饰符包括:new,public,protected,internal,private

常量的类型type是以下任何一种值类型或引用类型:sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型(enum-type)或引用类型(reference-type)。

class Foo {const double x = 3 //常量作为一个字段或属性 Foo(){const int y = 2//常量作为一个本地变量} }

(2),动态常量:readonly声明的常量叫动态常量,可以在声明时不初始化,而在构造函数中初始化,但必须每个构造函数中都要初始化;而且可以使用变量值初始化。可以作为一个实例的成员或一个静态类的成员。

class Foo {public const double X=1.0,Y=2.0//const常量可作为一个字段或属性, readonly float VALUE//常量命名最好全部大写 readonly int VALUE2 = 3 readonly StringBuilder SB public Foo(){VALUE= 9.80F SB = new StringBuilder()const int Z = 2//const常量也可作为一个本地变量 }public Foo(float value)//每个构造函数中都要初始化;而且可以使用变量值初始化 {VALUE=value }}

5,代码块

操作符{ … }表明一个代码块或新的范围。

void doSomething() {//代码块int a{//新的范围int b a = 1} a = 2 b = 3 //会出错,因为该变量声明于一个新的内嵌范围中 }

三,程序框架结构

一个C#应用程序由类及其成员构成,类和其他类型处于命名空间中,也可嵌套入别是类中。

C#基于.NET框架使用一种层次结构命名方案。要定位一个类型,必须同时指定类型所在的命名空间(逻辑组织结构)及实现该类型的程序集(物理组织结构)。

  • C#程序的逻辑组织结构从高层到低层为依次为:程序>命名空间>类型(类、结构、接口、枚举、委托等)>成员(字段、方法、属性和事件等)。

  • C#程序的物理组织结构则为:一个或多个.cs源文件=⇒编译器(合并所有源文件然后按照命名空间进行归类)编译打包=⇒程序集文件(.exe应用程序或.dll类库)

  • 源文件和程序集的关系比较自由:一个源文件可以包含多个程序集,一个程序集也可以分成几个源文件。

  • 源文件和命名空间的关系比较自由:同一命名空间(公共类型)可以自由分写在不同源文件中,一个源文件也可以自由地声明零个或多个命名空间,且源文件命名自由(无须匹配公共类型名),各个源文件从概念上能够自由地相互引用。所以在C#中向前声明是没有必要的,原因就是声明的顺序无关紧要。

  • 程序集和命名空间的关系也比较自由:一个程序集可以跨越多个命名空间,一个命名空间也可以包含多个程序集.

1,程序典型框架

C#程序.cs源文件典型框架:

/*多行注释语句包含在"反斜杠* "和" *反斜杠"中, 单行注释包含在或者两个反斜杠和换行符之中, 或者三个反斜杠和换行符之中(可以被VS自动识别为文件注释以提取) 要注意注释中的\,该续行符会把下一行连上来一起注释掉出错。*/ //要注意防止注释嵌套出错,可用#if 0...#endif预处理语句来嵌入注释。   using System//引用.NET框架中的类库资源 namespace YourNamespace//使用程序代码命名空间 {class YourClass//类{}struct YourStruct//结构{}interface IYourInterface//接口{}delegate int YourDelegate()//委托enum YourEnum //枚举{}namespace YourNestedNamespace//嵌套的命名空间{struct YourStruct //结构{}}class YourMainClass//应用程序主类{/*C#可执行程序的入口是Main方法,程序的执行从Main方法开始, 到Main方法结束。但动态链接库DLL程序可以没有Main方法。 入口方法唯一且为一个类中的静态方法,通常无返回值void(也可返回int) 通常传递进该方法的是字符串数组类型的命令行参数*/static void Main(string[] args) //入口方法{//入口执行语句块包含在{}中 int MyInterger//语句以;结束stringMyString///编译器会忽略空白字符(空格/回车/TAB) MyInterger = 17 //注意编译器对大小写敏感}} }

2,名称空间和using指令

名称空间是一种从逻辑上组织相关类和其他类型的方式,可以用来组织大型代码项目。名称空间以 . 运算符分隔。

global 命名空间是“根”命名空间:global::system 始终引用 .NET Framework 命名空间 System。global是命名空间别名限定符,防止名称冲突(命名空间污染)的,因为如果你也定义(或工程中引用了别人某处定义了)同名空间的类就会出问题。当左侧的标识符为 global 时,对右侧标识符的搜索将从全局命名空间开始。

asp.net1.1,vs2003默认情况下,C#创建的每个可执行文件都包含一个与项目同名的命名空间。

.net2.0&vs2005项目名称随机产生,也取消了vs2003自动生成的与项目同名的命名空间。

using system //引用.NET框架的应用程序根命名空间system,之后就能在全局名称空间引用system中的众多类。   namespace 空间名称 //声明自己的命名空间以控制类名称和方法名称的范围  {     using 空间名称2.代码2//之后就能在代码1处直接引用代码2     代码1     namespace 空间名称2     {     代码2     }  }   using colAlias = System.Collections //别名 namespace System //自定义了System命名空间,造成命名冲突可能 {classTestClass{static void Main(){// Searching the alias:别名可正常使用 colAlias::Hashtable test = new colAlias::Hashtable() // Add items to the table. test.Add("A", "1") test.Add("B", "2") test.Add("C", "3") foreach (string name in test.Keys){//要加上global::来引用 System.Console 类 global::System.Console.WriteLine(name + " " + test[name])}}} }

四,运算符:

按优先级顺序排列

算术运算符:前缀的++-- ,前缀一元的+-*/ 求余 %+- 位移运算符:<<, 比较运算符:小于 < 大于 小于等于 <= 大于等于 = 比较运算符:==,!= 逻辑运算符:& 逻辑运算符:^ 逻辑运算符:| 逻辑运算符:&& 逻辑运算符:|| 比较运算符:等于 = *= /= %= += -= <<= = &= ^= |= 后缀的++--

1,运算符重载

意味着运算符可以在需要的地方被定义用来和类一起运算,非常有用且直观。

以下运算符可以重载:

一元运算符+ - !~++ -- trueflase   二元运算符+ - * / %&| <<   比较运算符== != < <= == //比较运算符必须被成对重载,如== 和 != 必须在一起重载

注意:所有的运算符重载都是类的静态方法。

public class Currency {   double val      public Currency(double val)   {     this.val=val   }       //重载一元运算符,使得我们能简单地将两个Currency对象相加,而不用自定义的Add()方法。   public static Currency operator+(Currency lhs , Currency lhs)  {     return ( new Currency (lhs.val + rhs.val))   }         public static bool operator== (Currency lhs , Curreny rhs) //重载比较运算符   {     return (lhs.val == rhs.val)   }     public static bool operator!= (Currency lhs , Curreny rhs) //与==运算符成对重载   {     return (lhs.val != rhs.val)   } }

2,用户定义的数据类型转换

C# 允许程序员在类或结构上声明转换,以便可以使类或结构与其他类或结构或者基本类型相互进行转换。转换的定义方法类似于运算符,并根据它们所转换到的类型命名。

在 C# 中,可以将转换声明为 implicit(需要时自动转换)或 explicit(需要调用转换)。所有转换都必须为 static,并且必须采用在其上定义转换的类型,或返回该类型。

类之间的数据类型转换:两个限制:

  • 如果某个类直接或间接继承了另一个类,就不能在这两个类之间进行类型转换(这些类型的类型转换已经存在)。

  • 数据类型转换必须在源或目标数据类型定义的内部定义。

Implicit

Explicit

as

3,空接合运算符Null coalesce operator:??

??操作符由C#2.0加入

(??) 用于如果类不为空值时返回它自身,如果为空值则返回之后的操作

object nullObj = null object obj = new Object() return nullObj ?? obj // returns obj   //主要用作将一个可空类型赋值给不可空类型的简便语法 int? i = null int j = i ?? 0 // Unless i is null, initialize j to i. Else (if i is null), initialize j to 0.

五,流程控制结构

1, 条件语句

A,If语句

:通用判断

  If (条件1)     代码1   Else     代码2   If (条件1)   {}   Else   {}

B,Switch语句

用于同条件多结果判断

  Switch (条件)//条件不但象C/C++般可以是int或char,还可以象VB般是string //因为C#可以把字符串当成常量表达式来使用。而且在C#中case标签的引用值允许是null    {     Case 结果1:      代码1    break     Case 结果2:      代码2    goto default     Case 结果3:      代码3    goto Case 结果2//此时Case..相当于一个Label     Case 结果4:      代码4    Return     Case 结果5:goto Case 结果6;     Case 结果6:goto Case 结果7;     Case 结果7:      代码567//只要满足上面三个Case之一就执行。 //switch语句不准遍历,要求每个标签项后必须使用break或goto,这是C#和C/C++的区别    break     ...    Default:     代码     break    }  

C,三元运算语句

(条件)?True结果:False结果

常用于简单赋值语句:string myString = (myInteger<10)?”Less than 10”:“Great than or equal to”; 或者用于简单格式化文本语句:Console.WriteLine(“I am {0} year{1} old.”,myinteger,myinteger==1?””:“s”);

2,循环语句

A,do-while语句:

当条件为True时循环。

  Do   {...}   While(条件)//分号不可少

B,while语句:

当条件为True 时循环。

  While(条件)   {...}

C,for语句:

使用计数器循环。

  For (变量条件操作)//可以在此时声明变量,但作用域就仅限于循环内了。   {...   Break//跳出整个循环   Return   Continue//中止当前循环,继续下一个循环   Goto 标签//禁止从循环外部用goto跳入循环内部   }

D,foreach语句:

foreach (类型 标识符 in 表达式) embedded-statement

3,跳转语句:

A,Labels and goto statement

B,break statement

C,continue statement

4、条件编译

A,预处理指令(pre-processing directives):

并不是编译器开始编译代码之前的一个单独的处理步骤,它是作为词法分析的一部分来执行的。预处理指令都以#号开头并位于行首(前面可以出现空格符),定义符号的预处理指令:#define;取消符号定义的预处理指令:#undef。

#define COUNT /*这里定义了符号COUNT 它的作用域是该定义所在的整个文件 符号定义必须放在所有其它语句的前面 或者说是放在所有“实代码”(real code)的前面。 */

#undef COUNT /*作用域也是定衣所在的整个文件 它也必须出现在所有“实代码”之前。 */

B,条件编译指令:

#if…#elif…#else…#endif

//先后顺序: 一条#if语句(必须有) 零或多条#elif语句 零或一条#else语句 一条#endif语句(必须有)

C,发生错误和警告信息:

预编译和条件编译指令可以帮助我们在程序执行过程中发出编译的错误或警告,相应的指令是#error和#warning。

5、异常处理语句:

在c#中系统级的异常如溢出,零除数等,由于有一个定义完好的异常类因而可以等同于应用程序级错误条件。由于我们对待异常的态度往往是:捕捉、清除、继续执行程序,因此我们需要在程序中使用try-catch(s)-finally结构。

try//用于检查发生的异常,并帮助发送任何可能的异常。 { 程序代码块; } catch(Exception e)//以控制权更大的方式处理错误,可以有多个catch子句。 { 异常处理代码块; } finally //无论是否引发了异常,finally的代码块都将被执行。 { 无论是否发生异常,均要执行的代码块; }   //throw 用于引发异常,可引发预定义异常和自定义异常。

public class DivisorIsZero { private static void Main() { int dividend=10 int divisor1=0 int divisor2=5 int DivideValue try { DivideValue=dividend/divisor1//此A行命令执行则会抛出一个异常, //如果没有catch语句,程序会异常终止, //使用不带参数的catch子句,则可以捕获任意类型的异常。 //DivideValue=dividend/divisor2; //如果将上面A行注释掉,启用此B行, //这意味该程序运行时不会出现异常,从输出可知,finally代码块仍将被执行。 System.Console.WriteLine("DivideValue={0}",DivideValue)//(3)这一行将不会被执行。 } catch { System.Console.WriteLine("传递过来的异常值为:{0}",e) } finally { System.Console.WriteLine("无论是否发生异常,我都会显示。") } } }   /*可以给try语句提供多个catch语句,以捕获特定的异常, 如上例中:0作为除数则会引发DivideByZeroException类型的异常, 上例中的catch语句可以作如下修改:*/ catch(DivideByZeroException e) {System.Console.WriteLine("零不能作为除数!异常值为:n{0}",e) } catch(Exception e)//用于捕获除上述情况的其它的异常 {System.Console.WriteLine("并非''零作为除数引发的异常"!异常值为:n{0}",e); }

定义自己的异常类:除了预定义的异常外,我们还可以创建自己的异常,过程比较简单:

㈠声明一个异常,格式如下: class ExceptionName:Exception{}

㈡引发自己的异常:throw(ExceptionName);

六,数据类型

C#如同C/C++一样是一种强类型语言,即每个变量与常量在被声明后就有了一个固定的类型。数据类型可分为值类型和引用类型等:

  • 值类型(Value Types):类型的实例内存顺序分配在栈(stack)中,且和变量绑定。每个变量直接包含自身的所有数据,每创建一个变量,就在内存中开辟一块区域。无需事先分配内存,无需new一个变量,直接声明即可使用。包括:大部份内置类型(不包括string和object类型)、结构类型(struct)、枚举类型(enum)。

  • 引用类型(Reference Types,参考类型):存储的是一个对象的地址,所谓对象就是一个类的实例。每创建一个变量,就增加一个指向目标数据的指针。内存非线性分配在堆(Heap)中,当它们不再被使用时CS通过垃圾收集器自动释放内存(C++用delete)。它们使用new运算符来创建。

  • 指针类型:指针类型是用来操作内存的。(不常使用)

数据类型的另外一种划分方法是内置型和自定义型。

  • 内置数据类型(简单值类型,简单数据类型,简单类型,内置数据类型,基本型,内置型,基元数据类型,纯量类型):是指所有基元数据类型都是.net FrameWork库中System 命名空间中的预定义类型对象。

  • 用户自定义型包括:结构,枚举,类,接口,数组,集合,委托。其中结构和枚举也称为复合型类型:复合类型则是(即简单内置类型的复合)。

(一).数据类型全面对象化

C#的比JAVA更加彻底面向对象体现之一就是.NET内置数据类型也全面对象化了,通过默认的装箱动作封装成了类。所有基元数据类型都是.net FrameWork库中System 命名空间中的预定义类型对象。数据类型名称就是System 命名空间中的预定义类型的简称(或别名)。例如,int 是 System.Int32 的简称,而 double 是 System.Double 的简写。sbyte = System.SByte,…

所有的值类型都隐式地继承自 System.ValueType类型(注意System.ValueType本身是一个类类型),System.ValueType和所有的引用类型都继承自 System.Object基类。你不能显示地让结构继承一个类,因为C#不支持多重继承,而结构已经隐式继承自ValueType。

值类型的内存开销小,访问速度快,但是缺乏面向对象的特征;引用类型的内存开销大(在堆上分配内存),访问速度稍慢。

当使用C#时对象都是在内存的堆上创建和存取的,这些对象都是引用类型,而像int这样的基本类型以值类型对待

每当把一个值赋给一个值类型时,该值实际上被复制了。相比,对于引用类型,仅是引用被复制了,而实际的值仍然保留在相同的内存位置。

(二),值类型

值类型的实例存储于栈中,且和相应变量绑定。当声明一个变量为值类型后,内存会立即分配。当变量过了生存范围后,值类型的对象也随之销毁。

1,结构(Structures,structs)

结构是用户自定义值类型,结构和类很相似,但结构更适合于轻量级的类型。

把一系列相关的信息组织成为一个单一实体的过程,这就是创建一个结构的过程。

  struct 结构名:   {    访问方式1 变量类型1 变量名1//访问方式public/private    访问方式2 变量类型2 变量名2      ...   }   结构名 结构变量名   结构变量名.枚举值=...;

(结构是一种堆栈分配的复合数据类型,它不支持继承。在其他许多方面,结构与类非常相似。结构提供一种将相关字段和方法组合在一起的轻量方法,以便在紧凑循环和其他性能关键的方案中使用。)(在C#中,所有内置的简单数据类型其实都是一个结构,那么它们便具有结构数据类型的特点,有着属于自己的成员,如变量、常量、方法等,例如int类型包含有MaxValue、MinValue、ToString等成员。)

结构和枚举一样也是一种用户自定义的数据类型,C#中的结构实质上是一个类,主要用于只是想将一些数据组织到一起的情况。用关键字struct来定义。

C#中的结构具有类的其他特性,如实现构造函数和方法、支持嵌套等,但是不支持继承(除了它们派生于System.ValueType和System.Object类之外)和派生。不同的是,结构是值型的,存储在堆栈里,而且没有析构函数,不会被无用单元收集器清除掉。

定义结构的方法和定义类的方法一样。 结构中,除了包含变量外,还可以有构造函数(constructor)、常数(constant)、方法(method)等。结构不能有析构函数。下面的范例可以形象地展示结构类型的用法:

using Systempublic structCircle{public double r //定义一个成员变量public const double pi=3.1415926 //定义一个常数public Circle(double radius) //结构构造函数必须带参数{ r=radius}public double Area(){return pi*r*r //计算面积的成员方法}public double Circumstance(){return 2*pi*r //计算周长的成员方法}}public classStructShow{public static void Main(){ Circle MyCircle=new Circle(2) //定义了Circle结构类型的实例对象 Console.WriteLine("The radius of the circle: "+MyCircle.r) Console.WriteLine("The area of the circle: "+MyCircle.Area()) Console.WriteLine("The circumstance of the circle: "+MyCircle.Circumstance())}} 范例程序运行的结果是: The radius of the circle: 2 The area of the circle: 12.5663704 The circumstance of the circle: 12.5663704

2,预定义类型

即基元数据类型,全都属于结构类型。

内置型可再细分为整数类型、字符类型、实数类型和布尔类型

简称

.NET 类

类型

宽度

范围(位)

默认值

byte

Byte

无符号整数

8

0 到 255

0

sbyte

SByte

有符号整数

8

-128 到 127

0

int

Int32

有符号整数

32

-2,147,483,648 到 2,147,483,647

0

uint

UInt32

无符号整数

32

0 到 4294967295

0

short

Int16

有符号整数

16

-32,768 到 32,767

0

ushort

UInt16

无符号整数

16

0 到 65535

0

long

Int64

有符号整数

64

-922337203685477508 到 922337203685477507

0

ulong

UInt64

无符号整数

64

0 到 18446744073709551615

0

float

Single

单精度浮点型

32

-3.402823e38 至 3.402823e38

0.0

double

Double

双精度浮点型

64

-1.79769313486232e308 至 1.79769313486232e308

0.0

char

Char

单 Unicode 字符

16

文本中使用的 Unicode 符号

'\u0000'

bool

Boolean

逻辑布尔值类型

8

True 或 False。不接受任何整数类型。

false

decimal

Decimal

十进制财务专用精确小数类型或整型,可以表示带有 29 个有效位的十进制数

128

±1.0 × 10e−28 至 ±7.9 × 10e28

0

(1),整数类型:数学上的整数可以从负无穷到正无穷,但是计算机的存储单元是有限的,所以计算机语言提供的整数类型的值总是一定范围之内的。C#有九种数据类型:短字节型(sbyte)、字节型(byte)、短整型(short)、无符号短整型(ushort)、整型(int)、无符号整型(unit)、长整型(long)、无符号长整型(ulong)。划分的根据是该类型的变量在内存中所占的位数,各种类型的数值范围及所占内存空间。

注意:位数的概念是以二进制来定义的,比如说8位整数,则表示的数是2的8次方,为256。

以下的范例可以清楚地看出,当某类型的变量取值大小溢出该类型的数值范围时,计算机的处理方式:

using Systempublic classValueOut{public static void Main(){int i=2147483647 //定义变量为整型的最大值 Console.WriteLine(i) i++; //变量数值加1,溢出整型的数值范围。如果改为i=+2;则溢出结果不同 Console.WriteLine(i)}}   程序运行结果为: 2147483647 -2147483648

(2),布尔类型:是用来表示“真”和“假”两个概念的,在C#里用“true”和“false”来表示。值得注意的,在C和C++中,用0来表示“假”,用其他任何非0值来表示“真”。但是这种表达方式在C#中已经被放弃。在C#中,true值不能被其他任何非零值所代替。整数类型与布尔类型之间不再有任何转换,将整数类型转换成布尔型是不合法的,例如:

bool WrongTransform=1 //错误的表达式,不能将整型转换成布尔型

(3),实数类型:数学中的实数不仅包括整数,而且包括小数。小数在C#中主要采用两种类型来表示:单精度(float)和双精度(double)。它们的主要差别在于取值范围和精度不同。程序如果用大量的双精度类型的话,虽然说数据比较精确,但是将会占用更多的内存,程序的运行速度会比较慢。

单精度:取值范围在正负1.5×10e-45到3.4×10e38之间,精度为7位数。

双精度:取值范围在正负5.0×10e-324到1.7×10e308之间,精度为15到16位。

十进制类型(decimal),高精度、128位数据类型,它所表示的范围从大约1.0×10-28到7.9×10e28的28到29位有效数字。十进制类型的取值范围比doublc类型的范围小很多,但它更精确。

C#一个重要的优点是专门提供了decimal类型用来精确表示财务计算,但应注意decimal类型不是基本类型,所以在计算时使用时程序会有性能损失。

/*注意:当定义一个decimal变量并赋值时,可以在赋值数字的后面加上字符M(或m) 如果省略了m,在变量被赋值之前,它将被编译器当作双精度类型来处理。*/ decimal d_value=1.0m

(4),字符类型(char):C#采用Unicode字符集。

可以按下面的方法给一个字符变量赋值:

char c="C" //给字符变量赋值 chard= '\x0065' //16进制转义符\x chare= '\u0065' //Unicode转义符\u

3,枚举Enumeration类型

是一种由一组已命名的整型常量组成的数据类型。主要用于表示一个逻辑相关联的项和组合。使用关键字enum来定义。

枚举继承自System.Enum类,可以把”枚举类型的变量”看作”实例化System.Enum枚举类的对象”,可以使用System.Enum类下的所有公开方法。声明一个枚举类型的变量其实有点像设置一个数组的元素似的。

System.Enum从类型System.ValueType派生。

  enum 枚举名:枚举值类型//默认是int,也可用long,short和byte等整数类型,)   {    枚举值1=...,//不赋值的话,第一个常量的默认值为0    枚举值2=..., 枚举值3=枚举值2 + 400,//可使用表达式来初始化枚举值    枚举值4,//不赋值的话,默认为前面最后一个明确具体值的值递增1    ...   }   枚举名 变量名=枚举名.枚举值//用户可以在自己的代码中声明枚举型变量。但需要限定枚举成员的名字。   Season++; //枚举变量可自增自减,则Season.Spring (1)成为Season.Summer (2).   Season--;

(二).引用类型:

为引用类型创建的变量是托管引用类型的。当构建器(即对象)在堆上创建时,一个引用类型就被分配给该变量。当变量超出生存范围时该引用失效,当一个对象中的引用失效时对象被标记为垃圾,由回收器自动收集销毁。

当引用类型未引用任何对象时,一个引用类型变量是null。

1,数组(array)

数组主要用于同一数据类型的数据进行批量处理。在C#中,数组需要初始化之后才能使用。

如:int[] array1 = new int[3]{2,3,5};

int[] array1 = {2,3,5};

(注意)对规则多维数组,调用Length属性所得的值为整个数组的长度;而调用其GetLength方法,参数为0时得到数组第1维的长度,为1时得到数组第2维的长度,以此类推。而对于不规则多维数组,调用Length属性和以0为参数调用其GetLength方法,得到的都是第一维的长度。

(1),一维数组

变量类型[] 数组名 = new 变量类型[元素个数]{元素0,元素1,元素2…}

元素个数必须是整数或者整数常量,而且必须与后面的元素列值个数相同,否则出错。元素个数的new声明和后面的元素列值可以只选一个,就能声明并初始化数组。

遍历方法

A,For循环到.Length for(i=0,i<friendNames.Length,i++) { Console.WriteLine(friendNames[i]) } B,Foreach进行只读访问 foreach(string listName in friendNames) { Console.WriteLine(listName) }

(2),二维数组(多维)

变量类型[,] 数组名 = new 变量类型[一维元素个数,二维元素个数]{{元素00,元素01,元素02…},{元素10,元素11,元素12…}…}

(3),直角数组(交错数组,数组中的数组)

数组的五种声明方式:

int[]arrayarray=newint[2] //第二种声明方式 int[]array1=newint[2] //第三种声明方式 int[]array2={1,2,3} //第四种声明方式 int[]array3=newint[]{1,2,3} //第五种声明方式 int[]array4=newint[3]{1,2,3} //数组大小也可以是变量 intcount=3int[]arr=newint[count]

2,类(class)

类是自描述的用户自定义的引用类型。

类是一组具有相同数据结构和相同操作的对象集合。创建类的实例必须使用关键字new来进行声明。

类是面向对象的程序设计的基本构成模块。从定义上讲,类是一种数据结构,但是这种数据结构可能包含数据成员、函数成员以及其它的嵌套类型。其中数据成员类型主要有常量、域;函数成员类型有方法、属性、构造函数和析构函数等。

类是对一组具有相同属性和行为(即方法)的对象的描述,是对对象共同特征的描述。类包含成员变量和成员方法。

访问修饰符

  • private:私有的,类的内部可以访问,外部无法访问。

  • protected:受保护的,除了在类中可以访问外,该类的派生类也可访问。

  • public:公用的。成员变量和方法可以被任何外部类访问。

  • internal:内部的,在整个项目中都可以访问,项目外的代码不可以访问。

//类的声明: 访问修饰符 class 类名 //private/protected/public/默认为internal {//成员变量的声明 访问修饰符 数据类型 成员变量名;//internal/protected/public/默认为private }   //对象(实例)的创建 类名 对象名=new 类名()   public class YourClass //类头 //类体 {#region 变量public string name //声明公有成员变量,不规范的编程习惯,适于改动不大的快速小项目 private string phonepublic string Phonenumber //定义属性变量的另一种方法{ get { return phone } set { phone = value }} private string namepublic void setName(string nm){//do any checking you need,then name = nm}public int getName(){//do any checking you need,thenreturn name} //private const string sortCode="12-00-23";常量成员private readonly string sortCode//只读常量成员public MyClass(string sortCode){/*对构造函数中传来的字符串值设置了排序代码,this关键字用在方法中指示调用方法的对象,常用于消除本地和具有同名的类的变量的歧义。*/this.sortCode = sortCode} #endregion   public YourClass(){ //类的构造函数}private string name public void setName(string nm){//do any checking you need,then name = nm} public int getName(){//do any checking you need,thenreturn name}public string GetName(){return name //类的成员方法} ~YourClass(){ //类的析构函数} }

类和结构之间的差异

(重点)类和结构之间的根本区别在于:结构是值类型,而类是引用类型。当结构被声明后就分配于内存栈中,且结构变量和该地址绑定。类被声明后就以对象的形式被分配于内存堆中,类变量更象是指向该对象的托管的指针。

默认构造器

析构器

成员初始化

继承

类Classes

非必须(自动生成)

非必须

是(如果基类非密封)

结构Structs

必须(非自动生成)

必须

不支持

结构型适于快速访问和拥有少量成员的数据类型。如果涉及量较多,你应该创建一个类来实现他。

3,string类类型:

string类是一组由Unicode字符(char)组成的固定不变(修改字符串实际上是删除旧字符创建新字符)的系列。可以视为一个只读数组。

string不是结构类型,也不是基元数据类型,而属于类类型。string是类System.String的别名。

string

String

字符序列

 

它是引用类型而非值类型

字符串操作

string myString = "I have a file."//定义声明字符串 string myString2 = "Path is D:\\Book\\Happy.txt."//反斜杠“\”用作转义符 string MyString3 = @"Path is D:\Book\Happy.txt"//@可使两个双引号内的字符强制不转义 /* 双引号的转义符要么写"str\"str",要么写@"str""str" ,在VB.NET中才能用"str""str"*/ string MyString4 = "Name is \"Dream\" " string MyString5 = @"Name is ""Dream"" " string MyString6 = MyString1 + MyString2//运算符“+”可作连字符用 char myChar = myString[2//把string变量当作只读的char数组使用,不能改写myString[2] char[] myChars = myString.ToCharArray() char[]separator =' '//设定分隔符 string[] myWords =myString.Split(separator)//分隔成数组 Console.WriteLine("myString have {0} chars",myString.Length) myString=myString.ToLower()//转小写 myString=myString.ToUpper()//转大写 myString=myString.Trim()//删前后空格 myString=myString.TrimStart()//删前空格 myString=myString.TrimEnd()//删后空格 myString=myString.PadLeft(位数)//前补空格到指定位数 myString=myString.PadRight(位数)//后补空格到指定位数 myString=myString.PadLeft(位数,字符)//前补指定字符到指定位数 char[] trimChars ="e","#","*" myString = myString.trim(trimChars)//删指定字符 myString = "你\r\n好"//C#换行 myString = "你" & Environment.NewLine & "好"//C#和VB.net通用的灵活换行方法

4,接口(interface)

应用程序之间要相互调用,就必须事先达成一个协议,被调用的一方在协议中对自己所能提供的服务进行描述。在C#中,这个协议就是接口。接口定义中对方法的声明,既不包括访问限制修饰符,也不包括方法的执行代码。

(注意)如果某个类继承了一个接口,那么它就要实现该接口所定义的服务。也就是实现接口中的方法。

接口是包含成员定义却无实际实现的数据类型。可用于在不同数据类型之间要定义一个契约。可以声明方法,属性和索引器的定义,他们必须由一个类来实例化为公共成员。

interface IBinaryOperation {

double A { get; set; } double B { get; set; }

double GetResult(double a, double b); }

5,委托(delegate)

C#通过委托来提供类型安全的面向对象的指针。

委托用于封装某个方法的调用过程。

委托的使用过程分为3步:

(1).定义 delegate void HelloDelegate()   (2).实例化 HelloDelegate hd = new HelloDelegate(p1.Say) //p1.Say调用的方法   (3).调用 hd()   class Program {//Delegate typedelegate int Operation(int a, int b) static int Add(int i1, int i2){return a + b} static int Sub(int i1, int i2){return a - b} static void Main(){//Instantiate the delegate and assign the method to it. Operation op = Add //Call the method that the delegate points to.int result1 = op(2, 3) //5   op = Subint result2 = op(10, 2) //8} }   //Initializing the delegate with an anonymous method. addition = delegate(int a, int b){ return a + b }

6,事件Events

事件是可以指向多个方法的指针。就是把多个方法的指针绑定到一个标识符上。所以看上去就成了可委托的扩展。典型用法是UI开发中的触发器。用于C#以及其它CLI中的事件用法是基于传统VB的以下用法:

delegate void MouseEventHandler(object sender, MouseEventArgs e);   public class Button : System.Windows.Controls.Control { event MouseEventHandler OnClick;   /* Imaginary trigger function */ void click() { this.OnClick(this, new MouseEventArgs(data)); } }

事件需要跟随一个句柄(来自特定平台的对应库类如WPF和Windows Forms),一般跟随两个参数:sender和事件参数。事件参数对象的类型起源于CLI基本库其中一部份的EventArgs类。

事件声明之后,就可以从宿主中调用。一个监听方法就被实现,当事件被调用时就触发事件。

public class MainWindow : System.Windows.Controls.Window {private Button button1 public MainWindow(){ button1 = new Button() button1.Text = "Click me!" /* Subscribe to the event */ button1.ClickEvent += button1_OnClick /* Alternate syntax that is considered old: button1.MouseClick += new MouseEventHandler(OnClick); */} protected void button1_OnClick(object sender, MouseEventArgs e){ MessageBox.Show("Clicked!")} }

7,可空类型Nullable types (C#2.0.)

可空类型 (跟个问号, 如 int? i = null;) 允许设置 null 给任何类类型。(起初可空类型被引入C#是用于对数据库操作时,允许值类型为空)

int? i = null object o = i if (o == null) Console.WriteLine("操作正确 - 运行时为2005年9月之后版本") else Console.WriteLine("操作不正确 - 运行时为2005年9月之前版本")   //实际上等效于使用Nullable<T>结构 Nullable<int n = 2 n = null   Console.WriteLine(n.HasValue)

8,指针Pointers

C# has and allows pointers to value types (primitives, enums and structs) in unsafe context: methods and codeblock marked unsafe. These are syntactically the same as pointers in C and C++. However, runtime-checking is disabled inside unsafe blocks. static void Main(string[] args) {

unsafe { int a = 2; int* b = &a;

Console.WriteLine(“Address of a: {0}. Value: {1}”, (int)&a, a);

Console.WriteLine("Address of b: {0}. Value: {1}. Value of *b: {2}", (int)&b, (int)b, *b);

Will output something like: Address of a: 71953600. Value: 2

//Address of b: 71953596. Value: 71953600. Value of *b: 2 }

}

9,Dynamic (C#4.0)

C# 4.0 新增 dynamic关键字,提供動態編程(dynamic programming),把既有的靜態物件標記為動態物件,類似javascript, Python 或 Ruby。 dynamic calc = GetCalculator() int sum = calc.Add(10, 20)   Type dynamic is a feature that enables dynamic runtime lookup to C# in a static manner. Dynamic is a static "type" which exists at runtime. dynamic x = new Foo() x.DoSomething() //Will compile and resolved at runtime. An exception will be cast if invalid.

七,数据类型转换

1,数值转换

数值的转换有一个原则,即从低精度类型到高精度类型通常可以进行隐式转换;而从高精度类型则必须进行显式转换。

如:int i = 100 long j = 1000 j = i //隐式转换,由低精度到高精度的转换 i = (int)j //显式转换(强制类型转换),有高精度到底精度的转换

具体转换过程中信息的丢失就看各数据类型的精度了。

隐式转换:从低精度的转换到高精度的,所以不可能转换到char;另外可以把0隐式转换成枚举型,其他整数不行。装箱转换实际上就是一种隐式类型转换。

显式转换:拆箱转换就是一种显式转换。(显式转换并不是总能成功,而且常常可能引起信息丢失),显式转换包括所有的隐式转换,任何系统允许的隐式转换写成显式转换的形式都是允许的。

static void Main(string[] args) {short shortResult, shortVal = 4int integerVal = 67long longResultfloat floatVal = 10.5Fdouble doubleResult, doubleVal = 99.999string stringResult, stringVal = "17"bool boolVal = true Console.WriteLine"Variable Conversion Examples\n数据类型转换范例\n") doubleResult = floatVal * shortVal Console.WriteLine"Implicit,->double:{0}*{1}->{2}", floatVal, shortVal, doubleResult) shortResult =short)floatVal Console.WriteLine"Implicit,->short:{0}->{1}", floatVal, shortResult) stringResult = Convert.ToString(boolVal) + Convert.ToString(doubleVal) Console.WriteLine"Explicit,->string:\"{0}\"+\"{1}\"->{2}", boolVal, doubleVal, stringResult) longResult = integerVal + Convert.ToInt64(stringVal) Console.WriteLine"Mixed,->long {0}+{1}->{2}", integerVal, stringVal, longResult) }

2,枚举转换:枚举类型与其他任何类型之间不存在隐式转换。而和枚举类型相关的显式转换包括:

  • ①从所有整数类型(包括字符类型)和实数类型到枚举类型的显式转换;

  • ②从枚举类型到所有整数类型(包括字符类型)和实数类型的显式转换;

  • ③从枚举类型到枚举类型的显式转换。

3,转换检查:如果出现转换失败,程序就会抛出一个System.InvalidCastException异常

4,装箱和拆箱转换Boxing and unboxing

因为C# 将所有基元数据类型当作对象表示,数据类型名称就是System 命名空间中的预定义类型的简称(或别名)。例如,int 是 System.Int32 的简称,而 double 是 System.Double 的简写。sbyte = System.SByte,…所以可以在基元数据类型上调用对象方法。

C#借助自动装箱拆箱(值类型与引用类型之间相互转换)来完成此操作。如:

int foo = 42// Value type. object bar = foo//装箱(Box) 值类型-->等值的引用类型 System.Console.WriteLine(bar.ToString()) int foo2 = (int)bar //拆箱(UnBox,取消装箱) 引用类型-->值类型

装箱过程:C#中的装箱是隐性的implicit

  • 在堆上为新生成的对象(该对象包含数据,对象本身没有名称)分配内存。

  • 将 堆栈上 值类型变量的值拷贝到 堆上的对象 中。

  • 将堆上创建的对象的地址返回给引用类型变量(从程序员角度看,这个变量的名称就好像堆上对象的名称一样)。

拆箱过程:需要注意的是UnBox操作需要显示类型转换(explicit type cast)即显示声明拆箱后转换的类型。

  • 获取已装箱的对象的地址。

  • 将值从堆上的对象中拷贝到堆栈上的值变量中。

参见

堆和栈的区别|

我翻译成中文的Head First C#(第一页)| 《深入浅出C# 中文版 图文皆译 (更新第十二章DOC)》(Head First C# Chinese Edition)|

C#中的using 指令和命名空间| 如何:使用命名空间别名限定符(C# 编程指南)| 解决vs2005,ASP.NET2.0自定义命名空间问题|

C#程序集Assembly学习随笔(第一版)_AX| 什么是程序集?|

C#基础知识全面介绍|

C# 2.0程序设计教程|:C# 2.0宝典

第二章 基本数据类型、常量及变量|:高级语言程序设计|

c#数据类型基础| C#类型基础| 数据类型(C# 与 Java)| c#数据类型转换| 学习C#数据类型:string|

c#学习笔记(一)|:不错的«Microsoft.NET 编程语言 C#教程»自学摘记 c#学习笔记(二)| c#学习笔记(三)| c#学习笔记(四)|本地备份:c#学习笔记.doc|

CSharp3的语法

可视化语言文法形式化描述

C#程序设计教程 - Google 图书结果|

visual c#程序设计教程电子教案|:比较教科书式的粗疏教案

ASP.NET程序设计教程 第四章 c# 基 础 doc| 《 ASP.NET程序设计》 河南城建学院计算机科学与工程系 精品课程--ASP.NET| 《 ASP.NET程序设计》 第四章 C# 基 础

C#程序设计与案例教程| C#程序设计与案例教程 样章 C#语言基础|

Microsoft.NET 编程语言 C#教程| Microsoft .NET 編程語言-C#教程 PDF 2.0MB|

c# 异常处理 经典代码实例|

谈literal译名之选择|