第二讲 C#基础

类别:.NET开发 点击:0 评论:0 推荐:

第二讲  C#基础

 

为适应未来社会的发展,微软推出了.NET战略,以此作为下一代网络应用基础,微软的所有产品,包括操作系统、办公软件以及开发工具都将转移到.NET平台上。.NET所包含的技术全面先进,必将对今后的软件开发和应用形式产生巨大的影响。

    在.NET平台上,C#是微软为了适应未来网络技术的发展而推出的新一代编程语言,它是专为.NET战略开发的编程语言。

虽然.NET平台上包含多种编程语言,并且所有语言开发出的.NET应用程序效果也是一样的,但是,C#本身作为一种编程语言,它是从著名的C++ 进化而来的,并综合了C++ 和Java的优点,是.NET主推的语言,在.NET中起着不可或缺的作用,有志于在.NET平台上开发的程序员必须了解这种语言。

 

第一节   C#程序结构:

 

我们先来做一个最简单的控制台程序,并以此作为下一步试验的基础。

 

 

using System;

 

namespace cs1

{

    

     class Class1

     {

        

         //应用程序的主入口点。

         [STAThread]

         static void Main(string[] args)

         {

             

 

         }

     }

}

 

程序结构结构:

using System;

指明本程序引用的名称空间,后面需要用到的类,都要事先using进来。

 

namespace 语句

 

定义一个“语句”名称空间,这个程序定义的所有类,都位于这个名称空间下面,一个程序可以定义多个名称空间,一个名称空间可以包含多个类。但一个类只能处于一个名称空间下面。不同名称空间下相同名字的类,被认为是完全不同的东西。

 

static void Main(string[] args)

         {

             

         }

 

这是应用程序主入口点,用作方法的返回类型时,void 关键字指定方法不返回值。在方法的参数列表中不允许使用 void。例如,采用以下形式声明一个无参数的、不返回值的方法:void MyMethod();

 

我们的实验程序可以写到这个方法里面,比如:

 

static void Main(string[] args)

         {

              Console.WriteLine("您好,这是我的第一个C#程序");

 

     }

 

运行:

 

当然,后面我们也会讨论真正的Windows Form程序的写法,不过,控制台程序作为一个基础,你是必须要掌握的。

 

第二节   数据类型和运算符

 

一、              常数

 

   在C#语言中,有布尔型常数,数值型常数和数值型常数。

 

2-1布尔型常数

 

   布尔型常数只有true和false两个值,它们也是关键字。实际上在C语言中是没有这两个常数的,在那里是用0表示false,而其他非0数值表示true。但是在C#里面为了减少错误,还是加入了这两个常数,以保证语言的确定性。使用这个常数的更重要的原因,是.NET平台上不同语言布尔类型的数值并不相同,为了不同语言之间便于转换,请坚持使用true/false表示布尔类型的结果,这样利用中间语言,就可以实现不同语言之间的正确转换。

 

2-2数值型常数

 

数值型常数分为整形常数和浮点型常数。

整形常数:

十进制表示:2,100等;

十六进制表示(前面加0x):0x10(相当于十进制16);

这个区别要加以注意。

 

浮点型常数:

   

比如:1.25,-1.23 ,0.884, .884;

也可以用科学计数法:25e20(表示20乘以10的20次方)。

 

试验:

              Console.WriteLine(10);

              Console.WriteLine(0x10);

              Console.WriteLine(1.884);

      Console.WriteLine(2.4e25);

结果:

10

16

1.884

2.4E25

 

注意:在java里面,010表示八进制的8,但在C#中间并没有这种表示,它仍然是十进制的10,这些区别要加以注意。

 

字符型常数

 

    字符型常数包括单个字符和一串字符,也可以是不可打印的字符,如下表:

 

特殊字符

说明

\

续行符,表示下一行是本行的继续

\n

换行符

\b

退格

\r

回车

\f

走纸

\t

水平制表符

\v

垂直制表符

\\

反斜线

\’

单引号

\’’

双引号

\0

空字符,即字符0

 

    下面是一些合法的字符型常数:

 

    ‘A’,’B’,’\n’,’t’,’\\’

 

 

 

二、              标示符

 

  在C#中,标示符的第一个字母必须是下列之一:大小写英文字母,下划线(_),美元符($),其它都是错误的。

理论上,标示符的长度不受限制,但如果给类起名子,由于类是放在文件中的,所以名字要符合所用操作系统的规范。

定义变量的方法如下:

 

数据类型   标示符[,标示符……];

 

有些数据类型的变量,可以通过下面的方法转换数据类型

 

(数据类型)标示符

 

与C语言不同,变量一旦被声明,就会给它赋于初值,不同的变量初值是不同的。

第三节   基本数据类型和运算符

3-1 布尔型

布尔型用来处理逻辑判断,两目的布尔运算符见下表:

 

操作数1

操作数2

&(AND)

&&(AND)

|(OR)

||(OR)

^(XOR)

True

true

true

true

true

True

false

True

false

false

False

true

true

True

False

true

false

False

true

true

True

False

false

false

false

false

false

false

 

单目运算符

操作数

!(NOT)

True

false

False

True

 

要注意,&和&& 以及 |和||是有区别的:

&、|、^是位运算符,用于对两个整数进行位运算,它们同时也可以作为逻辑运算符,这点和C语言是一样的,但这点也值得探讨,因为C语言中逻辑真和假本来就是数字(1,0),当然可以进行位运算,但在java中,true和false是不能转换成数字的,所以用于逻辑运算从道理上就有点勉强了。

 

另外,还要看到位运算符和逻辑运算符在运算方式上也是不同的。

我们来看两个表达式:

(1)       true||false

(2)       true|false

在计算(1)的时候,系统只要看到true,就会计算出结果true,后面的部分就不管了。

而在计算(2)的时候,系统的确将true(看作1)和false(看作0)作了二进制计算,得到的是计算结果。

下面看一个例子:

 

int a=1;

         int b=2;

         Boolean c=true;

         Boolean d=false;

        

         Console.WriteLine(a|b);

          Console.WriteLine(c|d);

     Console.WriteLine(c||d);

 

结果:

3

true

true

 

第一个结果是3的原因在于:

     01

or   10

-----------

     11

这恰恰是十进制的3。

而如果写Console.WriteLine(c||d);将是错误的。

3-2 字符型

在C#中规定,字符型为16位Unicode编码(C中为8位),字符型可以通过转换转成整数型或浮点型,实际上,可以把字符型变成十六位无符号整数使用,整数的值是该字符Unicode编码。

字符型变量用char关键字声明,默认值为’\0’。

 

下面看一个例子:

 

char va='a',vb='b';

        

         Console.WriteLine(va);

         Console.WriteLine(vb);

         Console.WriteLine("String:"+va+vb);

         Console.WriteLine(va+vb);

         Console.WriteLine((int)va);

         Console.WriteLine((int)vb);

        Console.WriteLine(va==97);

      

 

结果应该是:

a

b

String:ab

195

97

98

true

 

第三行:自动转成字符串连接;

第四行:作加法运算的时候,系统自动把它转成整形数(Unicode编码),用其和输出;

第五、六行:输出的是其Unicode编码;

第八行:进一步验证了字符数据和对应的编码之间的关系。

3-3整形

下表显示了整型的大小和范围,这些类型构成了简单类型的一个子集。

 

类型            范围                                        大小

 

sbyte       -128 到 127                            有符号 8 位整数

byte        0 到 255                               无符号 8 位整数

char        U+0000 到 U+ffff                       16 位 Unicode 字符

short       -32,768 到 32,767                      有符号 16 位整数

ushort      0 到 65,535                            无符号 16 位整数

int         -2,147,483,648 到 2,147,483,647        有符号 32 位整数

uint        0 到 4,294,967,295                     无符号 32 位整数

long        -9,223,372,036,854,775,808

            到 9,223,372,036,854,775,807            有符号 64 位整数

ulong       0

            到 18,446,744,073,709,551,615           无符号 64 位整数

 

备注

如果整数表示的值超出了 ulong 的范围,将产生编译错误。

 

整形数据可以转成字符型和浮点型,一种整数型也可以转成另一种整数型,不过要注意,当长度大的向长度小的整数型转换的时候,可能丢失精度。

 

比如:

 

int i=350000;

     short j=(short)i;

     Console.WriteLine(i);

Console.WriteLine(j);

 

结果:

350000

22320

 

可以对整形数据进行操作的运算符有:

 

名称

运算符

进行运算的数据类型

运算结果类型

关系(双目)

<,<= ,= = ,!= ,>=, >

整形或者浮点型

布尔型

正负(单目)

+ , -

整形或者浮点型

与操作数一致

四则运算(双目)

+,-,*,/,%(取模)

整形或者浮点型

两个操作数都是整形时,结果为整形;有一个为浮点型是结果为浮点型。

增量和减量(单目)

++ ,--

整形或者浮点型

与操作数一致

位移(双目)

<<(左移一位),

>>(右移一位)

整形

整形

位自反(单目)

~

整形

整形

位运算(双目)

&(AND),|(OR),^(XOR)

整形

整形

 

当两个不同类型的操作数进行运算的时候,运算结果以较长位数的操作数为准。

下面是运算符的几个例子。

 

例一:

 

移位运算实际上是乘2或者除以2,而V 1<<V2,相当于V1*(2的V2次方);

V 1>>V2,相当于V1/(2的V2次方);

移位运算比实际的乘除速度要快得多。

 

下面的例子可以看到这个情况。

 

Console.WriteLine(1024<<2);

  Console.WriteLine(1024>>2);

 

结果是

4096

256

 

例二:增量运算

 

int k=10,l=10;

        

     Console.WriteLine(k);

     Console.WriteLine(l);

     k++;

     l++;

     Console.WriteLine(k);

  Console.WriteLine(l);

结果:

10

10

11

11

 

 

例三:除数为0的错误

 

int izero,g;

izero=0;

g=1/izero;

 

结果为:

 

 

3-4 浮点型

C#有两种浮点类型:

float    32位

double  64位

 

类型          大致范围                              精度

float          ±1.5 × E-45 到 ±3.4 × E+38         7 位

double        ±5.0 × E-324 到 ±1.7 × E+308       15 到 16 位

 

把浮点数转换成整数的时候,总是转换成接近0的那个整数。

 

Console.WriteLine((int)5.7);

       Console.WriteLine((int)5.1);

       Console.WriteLine((int)-5.7);

Console.WriteLine((int)-5.1);

 

结果为:

5

5

-5

-5

 

在使用浮点常数的时候,要注意一个问题:浮点常数总是作为double存放的,这和整数常数不同,所以,编译下面的例子就会出错:

 

     float f;

     f=3.56;

Console.WriteLine(f);

 

解决的办法,就是把浮点数强制转换为float类型。3.56f或者3.56F。

 

float f;

f=3.56F;

Console.WriteLine (f);

 

结果是:

3.56

 

货币类型:

Decimal 16  -79228162514264337593543950335 0.0000000000000000000000000001

                     到                                   到

            0.0000000000000000000000000001 79228162514264337593543950335

保留四位小数。

 

 

在C#中,对声明变量是赋了初值的:

 

基本数据类型           初值

布尔型            false

字符型            ‘\0’

整形              0

float              0.0f

double            0.0d

 

3-6 运算符小结:

    算术运算(二元):

    +(加), -(减),*(乘),/(除), %(取模,求余数);

 

    逻辑(布尔型和按位):

    &(与) |(或) ^(异或) !(非) ~(求反) &&(逻辑与) ||(逻辑或)

    true 和 false

 

    其中,前五个操作符(& | ^ ! ~)也可以用于位操作。

 

    字符串串联 +

 

    递增、递减 ++ --

    对操作数进行加一和减一操作,例如: x++,x--,++x,--x

 

    移位 << >>

    把操作数(int或long)移动指定的位数,其中<<左移,>>右移。

    例如:

    x<<1 (左移一位,相当于乘以2 )

    x>>2 (右移两位,相当于除以4 )

    注意,当进行左移操作的时候,被移出的高位将被忽略,低位将被填上0。

    当进行右移操作的时候,低位移出部分将被忽略,如果操作的是有符号数

(int或long),则高位填上符号位,如果是无符号数,则高位将填上0。

 

    关系(进行表达式的比较操作)

    ==(等于) !=(不等于) <(小于) >(大于)

    <=(小于等于) >=(大于等于)

 

    赋值

 

    (X += 100 相当于 X=X+100 )

 

    =(等于) +=(加等) -=(减等) *=(乘等) /=(除等)

    %=(模等) &=(与等) |=(或等) ^=(异或等)

    <<=(左移等) >>=(右移等)

 

    成员访问 .(用来访问类的成员)

 

    索引 []

    利用索引的方法访问数组、索引器或属性。

    例如:

    int[] arr, arr[0]=1;

 

    转换 ()

    用来进行类型转换操作

    例如:

    int a=(int)X    把x转换成整数后赋给a。

 

  条件 ?:

  这是一个三元操作符,这个操作符根据表达式的值返回两个值中的一个,

例如:

  int a=(x>0)?1:0 

    表示,如果x>0(true)则a=1,否则的话,a=0 

                             

    创建对象 New

 

3-6 运算的优先级

 

算符的优先级和顺序关联性当一个表达式包含多个运算符时,这些运算符的优先级控制各运算符的计算顺序。

例如,表达式 x + y * z 按 x + (y * z) 计算,因为 * 运算符具有的优先级比 + 运算符高。运算符的优先级由运算符的关联语法产生式的定义确定。例如,一个增量表达式由以 + 或 - 运算符分隔的乘法表达式组成,因此给 + 和 - 运算符赋予的优先级比 *、/ 和 % 运算符低。

 

下表按照从最高到最低的优先级顺序概括了所有的运算符:

 

    初等项 x.y  f(x)  a[x]  x++  x--  new

typeof  checked  unchecked

 

 

    一元 +  -  !  ~  ++x  --x  (T)x

 

    乘法 *  /  %

 

    加法 +  -

 

    移位 <<  >>

 

    关系和类型检测 <  >  <=  >=  is  as

 

    相等 ==  !=

 

    逻辑 AND &

 

    逻辑 XOR ^

 

    逻辑 OR |

 

    条件 AND &&

 

    条件 OR ||

 

    条件 ?:

 

    赋值 =  *=  /=  %=  +=  -=  <<=  >>=  &=  ^=  |=

 

 

当操作数出现在具有相同优先级的两个运算符之间时,运算符的顺序关联性控制运算的执行顺序:

除了赋值运算符外,所有的二元运算符都向左顺序关联,意思是从左;

向右执行运算。例如,x + y + z 按 (x + y) + z 计算;

赋值运算符和条件运算符 (?:) 都向右顺序关联,意思是从右向左执;

行运算。例如,x = y = z 按 x = (y = z) 计算。

 

优先级和顺序关联性都可以用括号控制。例如,x + y * z 先将 y 乘以 z 然后将结果与 x 相加,而 (x + y) * z 先将 x 与 y 相加,然后再将结果乘以 z。

 

 

第四节 C#的表达式

4-1 条件选择语句 

    if-else

 

    if 语句是表达式求得 true 值时执行代码块的控制语句。它的形式为:

 

    if (expression)

       statement1

    [else

       statement2]

 

   此处:

 

   expression

   一个表达式,可隐式转换为 bool 或包含重载 true 和 false 运算符的类型。

   statement1

   expression 为 true 时执行的嵌入语句。

   statement2

   expression 为 false 时执行的嵌入语句。

 

备注

如果 expression 为 true,则执行 statement1。如果可选的 else 子句存在并且 expression 求得 false 值,则执行 statement2。执行 if 语句之后,控制传递给下一个语句。

 

如果 if 语句的两个结果中有任何一个结果(true 或 false)导致执行一个以上的语句,则可通过将多个语句包括在块中按条件执行它们。

 

在测试条件时执行的语句可以是任何种类的,包括嵌套在原始 if 语句中的另一个 if 语句。在嵌套的 if 语句中,else 子句属于没有相应 else 的最后一个 if。例如:

private void button2_Click(object sender, System.EventArgs e)

         {

              int x;

              int y;

              string z;

              z=textBox1.Text;

              x=20;

              y=Int32.Parse(z);

              if (x > 10)

                   if (y > 20)

                       textBox2.Text="这是第一个";

                   else

                       textBox2.Text="这是第二个";

     }

 

注意:和VB.NET不同,C#中的等号是不能进行类型转换的,所以必须有下面的语句进行类型转换。

y=Int32.Parse(z);

 

在此例中,如果条件 (y > 20) 求得 false 值,则显示“这是第二个”。但如果要使 “这是第二个”与条件 (x >10) 关联,则使用大括号:

     private void button3_Click(object sender, System.EventArgs e)

         {

              int x;

              int y;

              string z;

              z=textBox1.Text;

              x=8;

              y=Int32.Parse(z);

              if (x > 10)

              {if (y > 20)

                       textBox2.Text="这是第一个";}

              else

                   textBox2.Text="这是第二个";

     }

 

 

 

在这种情况下,条件 (x > 10) 求得 false 值时将显示“这是第二个”。

 

例二:

 

第二个例子,可以体会一下“类”在这里的应用。先做一个类(可以放在最下面,也可以专门做一个类的文件)

public class IfTest

{

     public System.Windows.Forms.TextBox textB;

     public void Mychar(string c)

     {

         char s;

        s=c[0];

         if (Char.IsLetter(s))

              textB.Text="这是字母";

         else

              textB.Text="这不是字母";   

     }

}

 

在Form1中,写Button事件:

 

         private void button4_Click(object sender, System.EventArgs e)

         {

              IfTest Myclass;

              Myclass=new IfTest();

              string s;

              s=textBox1.Text;

              Myclass.textB=textBox2;

              Myclass.Mychar(s);

 

     }

这里,我们可以看到如何构造一个类的实例,并且通过引用传递,把类中的数据在textBox2种显示出来。

 

 

 

这里用到了字符类型,下面简要的说明一下:

char 类型的常数可以写成字符、十六进制换码序列或 Unicode 表示形式。您也可以显式转换整数字符代码。以下所有语句均声明了一个 char 变量并用字符 X 将其初始化:

 

char MyChar = 'X';        // Character literal

char MyChar = '\x0058';   // Hexadecimal

char MyChar = (char)88;   // Cast from integral type

char MyChar = '\u0058';   // Unicode

转换

char 类型可隐式转换为 ushort、int、uint、long、ulong、float、double 或 decimal 类型。但是,不存在从其他类型到 char 类型的隐式转换。

 

关于New的问题,后面我们还会进一步讨论。

 

还可以扩展 if 语句,使用下列 else-if 排列来处理多个条件:

 

if (Condition_1)

            Statement_1;

else if (Condition_2)

            Statement_2;

else if (Condition_3)

           Statement_3;

...

else

           Statement_n;

 

    示例

 

    此例检查输入字符是否是小写字符、大写字符或数字。否则,输入字符不是字母字符。程序利用 else-if 阶梯。

 

   下面再做一个类:

 

   public class IfTest2

{

     public System.Windows.Forms.TextBox textB;

     public void Mychar(string c)

     {

         char s;

         s=c[0];

         if (Char.IsUpper(s))

              textB.Text="这是大写字母";

         else if (Char.IsLower(s))

              textB.Text="这是小写字母";

         else if (Char.IsDigit(s))

              textB.Text="这是数字";

         else

              textB.Text="这不是字母或者数字";

     }

}

 

只要把类的声明语句稍稍改一下,就可以使用这个类的方法:

 

    private void button4_Click(object sender, System.EventArgs e)

         {

              IfTest2 Myclass;

              Myclass=new IfTest2();

              string s;

              s=textBox1.Text;

            Myclass.textB=textBox2;

              Myclass.Mychar(s);

 

         }

 

 

4-2 switch-case语句

 

 

    switch 语句是一个控制语句,它通过将控制传递给其体内的一个 case 语句来处理多个选择。switch 语句的形式为:

 

switch (expression)

{

   case constant-expression:

      statement

      jump-statement

   [default:

      statement

      jump-statement]

}

此处:

expression

一个整型或字符串型表达式。

statement

控制传递给 case 或 default 时执行的嵌入语句。

jump-statement

将控制传递到 case 体外部的跳转语句。

constant-expression

根据此表达式的值将控制传递给特定的 case。

备注

    控制传递给 constant-expression 与 expression 匹配的 case 语句。switch 语句可以包含任意数量的 case 实例,但同一 switch 语句中的两个case 常数不能具有相同的值。语句体从选定的语句开始执行,一直执行到 jump-statement 将控制传递到 case 体之外为止。

 

    请注意,每个块(包括最后一个块,不管它是 case 语句还是 default 语句)后都要有 jump-statement。与 C++ switch 语句不同,C# 不支持从一个 case 标签显式贯穿到另一个 case 标签。如果要使 C# 支持从一个 case 标签显式贯穿到另一个 case 标签,可以使用 goto 一个 switch-case 或 goto default。

 

如果 expression 不匹配任何 constant-expression,则控制传递给可选的 default 标签后面的 statement。如果没有 default 标签,则控制传递到 switch 之外。

 

类:

 

public class CaseTest

{

     public System.Windows.Forms.TextBox textB;

 

     public void MyCase(string s)

     {

         textB.Clear();

         int n = int.Parse(s); 

         int cost = 0;

         switch(n)      

         {        

              case 1:  

                   cost += 25;

                   //break 语句终止它所在的最近的封闭循环或条件语句。

                   //控制传递给终止语句后面的语句(如果有的话)

                   break;        

                  

              case 2:           

                   cost += 25;

                   goto case 1;          

              case 3:           

                   cost += 50;

                   goto case 1;        

              default:            

                   textB.Text="错误的选择,请输入 1, 2, or 3.";           

                   break;     

         }

         if (cost != 0)

                textB.AppendText(cost.ToString());

     }

}

 

 

事件程序:

 

     private void button1_Click(object sender, System.EventArgs e)

         {

              CaseTest Myclass;

              Myclass=new CaseTest();

              string s;

              s=textBox1.Text;

              Myclass.textB=textBox2;

              Myclass.MyCase(s);

         }

 

4-3 for循环

for 循环重复执行一个语句或一个语句块,直到指定的表达式求得 false 值为止。它的形式为:

 

    for ([initializers]; [expression]; [iterators]) statement

此处:

 

initializers

初始化循环计数器的表达式或赋值语句的逗号分隔列表。

expression

    一个表达式,可隐式转换为 bool 或包含重载 true 和 false 运算符的类型。此表达式用于测试循环终止条件。

iterators

递增或递减循环计数器的表达式语句。

statement

要执行的嵌入语句。

备注

for 语句按下列方式重复执行 statement:

 

首先,计算 initializers。

然后,当 expression 求得 true 值时,执行 statement 并计算 iterators。 当 expression 求得 false 值时,控制传递到循环之外。

由于 expression 的测试发生在循环的执行之前,因此 for 语句执行零次或更多次。

 

for 语句的所有表达式都是可选的;例如,下列语句用于写一个无限循环:

 

for (;;) {

   ...

}

示例

         private void button2_Click(object sender, System.EventArgs e)

         {

              textBox2.Text="";

              for (int i = 1; i <= 5; i++)

                   textBox2.AppendText(i.ToString()+"\r\n");

              //"\r\n"为转意字符

              //\r回车

             //\n换行

              //\b退格

             //\f换页

              //\'单引号

              //\"双引号

 

              }

 

4-4 foreach, in语句

 

foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用。此语句的形式如下:

 

foreach (type identifier in expression) statement

此处:

 

type

identifier 的类型。

identifier

表示集合元素的迭代变量。

expression

对象集合或数组表达式。集合元素的类型必须可以转换为 identifier 类型。

statement

要执行的嵌入语句。

备注

    嵌入语句为数组或集合中的每个元素继续执行。当为集合中的所有元素,完成迭代后,控制传递给 foreach 块之后的下一个语句。

 

示例

此例搜索一个整数数组中的偶数和奇数。每类数字的计数器存储该类数字出现的次数。

 

         private void button3_Click(object sender, System.EventArgs e)

         {

              int odd = 0, even = 0;

              int[] arr = new int [] {0,1,2,5,7,8,11};

 

              foreach (int i in arr)

              {

                   ///模数运算符 (%) 计算第二个操作数除第一个操作数后的余数。

                   if (i%2 == 0) 

                       even++;     

                   else

                       odd++;        

              }

              textBox2.Text="";

              for (int i = 0; i <= 6; i++)

                textBox2.AppendText(arr[i].ToString()+"  ");

              textBox2.AppendText("\r\n");

              textBox2.AppendText("偶数:"+even.ToString()+"\r\n");

              textBox2.AppendText("奇数:"+odd.ToString()+"\r\n");

         }

 

4-5 while循环

while 语句执行一个语句或一个语句块,直到指定的表达式求得 false 值为止。它的形式为:

 

while (expression) statement

此处:

expression

一个表达式,可隐式转换为 bool 或包含重载 true 和 false 运算符的类型。此表达式用于测试循环终止条件。

statement

要执行的嵌入语句。

备注

由于 expression 的测试发生在循环的执行之前,因此 while 循环执行零次或更多次。

 

当 break、goto、return 或 throw 语句将控制传递到循环之外时可以终止 while 循环。若要将控制传递给下一个迭代但不退出循环,请使用 continue 语句。

 

示例:

private void button4_Click(object sender, System.EventArgs e)

         {

              int n = 1;

            textBox2.Text="";

              while (n < 6)

              {

                   textBox2.AppendText("循环次数 "+n.ToString()+"\r\n");

                   n++;

              }

         }

4-6 do循环

do 语句重复执行一个语句或一个语句块,直到指定的表达式求得 false 值为止。它的形式为:

 

do statement while (expression);

此处:

 

expression

一个表达式,可隐式转换为 bool 或包含重载 true 和 false 运算符的类型。此表达式用于测试循环终止条件。

statement

要执行的嵌入语句。

备注

与 while 语句不同,do 语句的体循环至少执行一次,与 expression 的值无关。

 

示例,注意在第二个例子中,虽然条件求得 false 值,但循环将执行一次。

 

private void button5_Click(object sender, System.EventArgs e)

         {

              int x;

              int y = 0;

            textBox2.Text="";

              do

              {

                   x = y++;

                   textBox2.AppendText("循环次数 "+x.ToString()+"\r\n");

 

              }

 

              while(y < 5);

            textBox2.AppendText("第二个例子: "+"\r\n");

              int n = 10;

              do

              {

                   textBox2.AppendText("n的数字 "+n.ToString()+"\r\n");

                   n++;

              } while (n < 6);

        

         }

 

 

 

 

4-7   调转语句

 

break 语句终止它所在的最近的封闭循环或条件语句。控制传递给终止语句后面的语句(如果有的话)。break 语句的形式为:

break;

示例

在此例中,条件语句包含一个可以从 1 计数到 100 的计数器;但 break 语句在计数达到 4 后终止循环。

// statements_break.cs

using System;

class BreakTest

{

   public static void Main()

   {

      for (int i = 1; i <= 100; i++)

      {

         if (i == 5)

            break;

         Console.WriteLine(i);

      }

   }

}

输出

1

2

3

4

示例

此例在 switch 语句中演示了 break 的用法。

// statements_break2.cs

// break and switch

using System;

class Switch

{

   public static void Main()

   {

      Console.Write("Enter your selection (1, 2, or 3): ");

      string s = Console.ReadLine();  

      int n = Int32.Parse(s);

 

      switch(n)

      {

         case 1:

            Console.WriteLine("Current value is {0}", 1);

            break;

         case 2:

            Console.WriteLine("Current value is {0}", 2);

            break;

         case 3:

            Console.WriteLine("Current value is {0}", 3);

            break;

         default:

            Console.WriteLine("Sorry, invalid selection.");

            break;

      }

   }

}

输入

1

示例输出

Enter your selection (1, 2, or 3): 1

Current value is 1

如果输入了 4,则输出为:

Enter your selection (1, 2, or 3): 4

Sorry, invalid selection.

 

注意一下,C#里面break的用法和java并不一样。

 

第五节  方法调用语句

1)  ref参数声明方式

 

方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。

若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。

传递到 ref 参数的参数必须最先初始化。将此方法与 out 参数相比,后者的参数在传递到 out 参数之前不必显式初始化。

如果两个方法的声明只在 ref 的使用方面不同,则会发生重载。

属性不是变量,不能作为 ref 参数传递。

   实例:

 

    public static void TestRef(ref char i)

         {

             

              i = 'b';

         }

 

         public static void TestNoRef(char i)

         {

             

              i = 'c';

         }

 

         private void button1_Click(object sender, System.EventArgs e)

         {

              char i = 'a'; 

              TestRef(ref i); 

              textBox1.Text=i.ToString();

              TestNoRef(i);

              textBox2.Text=i.ToString();

         }

   }

 

 

2)out参数声明方式

 

方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。

 

当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。

若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。

不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。

如果两个方法的声明仅在 out 的使用方面不同,则会发生重载。

属性不是变量,不能作为 out 参数传递。

 

有关传递数组的信息,请参阅使用 ref 和 out 传递数组。

 

示例

 

 

         public static int TestOut(out char i)

         {

              i = 'b';

              return -1;

         }

         private void button2_Click(object sender, System.EventArgs e)

         {

        char i;

         textBox1.Text=TestOut(out i).ToString();

        textBox2.Text=i.ToString();

        }

 

3)params参数声明方式:

 

params 关键字可以指定在参数数目可变处采用参数的方法参数。

在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

 

示例

 

     void Useparams(params int[] list)

         {

              listBox1.Items.Clear();

 

              for (int i=0;i<list.Length;i++)

              {

             listBox1.Items.Add(list[i].ToString());

              }

         }

 

         void Useparams2(params object[] list)

         {

              listBox1.Items.Clear();

 

              for (int i=0;i<list.Length;i++)

              {

                   listBox1.Items.Add((object)list[i].ToString());

              }

         }

 

 

         //传递一个参数

         private void button1_Click(object sender, System.EventArgs e)

         {

         Useparams(1);

         }

 

         //传递三个参数

         private void button2_Click(object sender, System.EventArgs e)

         {

         Useparams(1,2,3);

         }

 

         //传递不同类型的参数

         private void button3_Click(object sender, System.EventArgs e)

         {

              Useparams2(1,'a',"test");

         }

 

         //传递数组

         private void button4_Click(object sender, System.EventArgs e)

         {

              int[] myarray=new int[3]{10,20,30};

              Useparams(myarray);

        }

 

4)new 关键字

 

在 C# 中,new 关键字可用作运算符或修饰符。

new 运算符 用于在堆上创建对象和调用构造函数。

new 修饰符 用于隐藏基类成员的继承成员。

 

a>new 运算符

 

new 运算符用于创建对象和调用构造函数,例如:

 

Class1 MyClass  = new Class1();

也用于为值类型调用默认的构造函数,例如:

 

int myInt = new int();

在上一个语句中,myInt 初始化为 0,它是 int 类型的默认值。该语句的效果等同于:

 

int myInt = 0;

有关默认值的完整列表,请参阅默认值表。

 

记住,为结构声明默认的构造函数是一个错误,因为每一种值类型都隐式具有一个公共的默认构造函数。但是,可以在结构类型上声明参数化的构造函数。

 

值类型对象(例如结构)是在堆栈上创建的,而引用类型对象(例如类)是在堆上创建的。

 

不能重载 new 运算符。

 

 

第六节   数组

7-1 一维数组

可以如下例所示声明一个由 5 个整数组成的数组:

 

int[] myArray = new int [5];

此数组包含从 myArray[0] 到 myArray[4] 的元素。new 运算符用于创建数组并将数组元素初始化为它们的默认值。在此例中,所有数组元素都初始化为零。

 

可以用相同的方式声明存储字符串元素的数组。例如:

 

string[] myStringArray = new string[6];

数组初始化

可以在声明数组时将其初始化,在这种情况下不需要级别说明符,因为级别说明符已经由初始化列表中的元素数提供。例如:

 

int[] myArray = new int[] {1, 3, 5, 7, 9};

可以用相同的方式初始化字符串数组。下面声明一个字符串数组,其中每个数组元素用每天的名称初始化:

 

string[] weekDays = new string[]

               {"Sun","Sat","Mon","Tue","Wed","Thu","Fri"};

如果在声明数组时将其初始化,则可以使用下列快捷方式:

 

int[] myArray = {1, 3, 5, 7, 9};

string[] weekDays = {"Sun","Sat","Mon","Tue","Wed","Thu","Fri"};

可以声明一个数组变量但不将其初始化,但在将数组分配给此变量时必须使用 new 运算符。例如:

 

int[] myArray;

myArray = new int[] {1, 3, 5, 7, 9};   // OK

myArray = {1, 3, 5, 7, 9};   // Error

值类型数组和引用类型数组

请看下列数组声明:

 

MyType[] myArray = new MyType[10];

该语句的结果取决于 MyType 是值类型还是引用类型。如果是值类型,则该语句将创建一个由 10 个 MyType 类型的实例组成的数组。如果 MyType 是引用类型,则该语句将创建一个由 10 个元素组成的数组,其中每个元素都初始化为空引用。

 

将数组作为参数传递

可以将初始化的数组传递给方法。例如:

 

PrintArray(myArray);

也可以在一个步骤中初始化并传递新数组。例如:

 

PrintArray(new int[] {1, 3, 5, 7, 9});

示例

在下例中,初始化一个字符串数组并将其作为参数传递给 PrintArray 方法(该数组的元素显示在此方法中):

 

// cs_sd_arrays.cs

using System;

public class ArrayClass

{

   static void PrintArray(string[] w)

   {

      for (int i = 0 ; i < w.Length ; i++)

         Console.Write(w[i] + "{0}", i < w.Length - 1 ? " " : "");

      Console.WriteLine();

   }

 

   public static void Main()

   {

      // Declare and initialize an array:

      string[] WeekDays = new string []

         {"Sun","Sat","Mon","Tue","Wed","Thu","Fri"};

 

      // Pass the array as a parameter:

      PrintArray(WeekDays);

   }

}

输出

Sun Sat Mon Tue Wed Thu Fri

7-2 多维数组

数组可以具有多个维度。例如,下列声明创建一个四行两列的二维数组:

 

int[,] myArray = new int[4,2];

另外,下列声明创建一个三维(4、2 和 3)数组:

 

int[,,] myArray = new int [4,2,3];

数组初始化

可以在声明数组时将其初始化,如下例所示:

 

int[,] myArray = new  int[,] {{1,2}, {3,4}, {5,6}, {7,8}};

也可以初始化数组但不指定级别:

 

int[,] myArray = {{1,2}, {3,4}, {5,6}, {7,8}};

如果要声明一个数组变量但不将其初始化,必须使用 new 运算符将数组分配给此变量。例如:

 

int[,] myArray;

myArray = new int[,] {{1,2}, {3,4}, {5,6}, {7,8}};   // OK

myArray = {{1,2}, {3,4}, {5,6}, {7,8}};   // Error

也可以给数组元素赋值,例如:

 

myArray[2,1] = 25;

将数组作为参数传递

可以将初始化的数组传递给方法。例如:

 

PrintArray(myArray);

也可以在一个步骤中初始化并传递新数组。例如:

 

PrintArray(new int[,] {{1,2}, {3,4}, {5,6}, {7,8}});

示例

在此例中,初始化一个二维数组并将其传递给 PrintArray 方法(该数组的元素显示在此方法中)。

 

// cs_td_arrays.cs

using System;

public class ArrayClass

{

   static void PrintArray(int[,] w)

   {

      // Display the array elements:

      for (int i=0; i < 4; i++)

         for (int j=0; j < 2; j++)

            Console.WriteLine("Element({0},{1})={2}", i, j, w[i,j]);

   }

 

   public static void Main()

   {

      // Pass the array as a parameter:

      PrintArray(new int[,] {{1,2}, {3,4}, {5,6}, {7,8}});

   }

}

输出

Element(0,0)=1

Element(0,1)=2

Element(1,0)=3

Element(1,1)=4

Element(2,0)=5

Element(2,1)=6

Element(3,0)=7

Element(3,1)=8

 

7-3 交错数组

交错数组是元素为数组的数组。交错数组元素的维度和大小可以不同。交错数组有时称为“数组的数组”。本主题包含声明、初始化和访问交错数组的示例。

 

下面声明一个由三个元素组成的一维数组,其中每个元素都是一个一维整数数组:

 

int[][] myJaggedArray = new int[3][];

必须初始化 myJaggedArray 的元素后才可以使用它。可以如下例所示初始化元素:

 

myJaggedArray[0] = new int[5];

myJaggedArray[1] = new int[4];

myJaggedArray[2] = new int[2];

每个元素都是一个一维整数数组。第一个元素是由 5 个整数组成的数组,第二个是由 4 个整数组成的数组,而第三个是由 2 个整数组成的数组。

 

也可以使用初始值设定项用值填充数组元素,在这种情况下不需要数组大小,例如:

 

myJaggedArray[0] = new int[] {1,3,5,7,9};

myJaggedArray[1] = new int[] {0,2,4,6};

myJaggedArray[2] = new int[] {11,22};

还可以在声明数组时将其初始化,如:

 

int[][] myJaggedArray = new int [][]

                        {

                           new int[] {1,3,5,7,9},

                           new int[] {0,2,4,6},

                           new int[] {11,22}

                        };

可以使用下列快捷方式(注意在元素初始化中不能省略 new 运算符,因为元素没有默认初始化):

 

int[][] myJaggedArray = {

                           new int[] {1,3,5,7,9},

                           new int[] {0,2,4,6},

                           new int[] {11,22}

                        };

可以如下例所示访问个别数组元素:

 

// Assign 33 to the second element of the first array:

myJaggedArray[0][1] = 33;

// Assign 44 to the second element of the third array:

myJaggedArray[2][1] = 44;

可以混合使用交错数组和多维数组。下面声明和初始化一个一维交错数组,该数组包含大小不同的二维数组元素:

 

int[][,] myJaggedArray = new int [3][,]

                         {

                            new int[,] { {1,3}, {5,7} },

                            new int[,] { {0,2}, {4,6}, {8,10} },

                            new int[,] { {11,22}, {99,88}, {0,9} }

                         };

可以如下例所示访问个别元素,该示例显示第一个数组的元素 [1,0] 的值(值为 5):

 

Console.Write("{0}", myJaggedArray[0][1,0]);

示例

下例生成数组 myArray,而此数组的元素为数组。每一个数组元素都有不同的大小。

 

// cs_array_of_arrays.cs

using System;

public class ArrayTest

{

   public static void Main()

   {

      // Declare the array of two elements:

      int[][] myArray = new int[2][];

 

      // Initialize the elements:

      myArray[0] = new int[5] {1,3,5,7,9};

      myArray[1] = new int[4] {2,4,6,8};

 

      // Display the array elements:

      for (int i=0; i < myArray.Length; i++)

      {

         Console.Write("Element({0}): ", i);

 

         for (int j = 0 ; j < myArray[i].Length ; j++)

            Console.Write("{0}{1}", myArray[i][j],

                          j == (myArray[i].Length-1) ? "" : " ");

 

         Console.WriteLine();

      }

   }

}

输出

Element(0): 1 3 5 7 9

Element(1): 2 4 6 8

7-4 使用 ref 和 out 传递数组

与所有的 out 参数一样,在使用数组类型的 out 参数前必须先为其赋值,即必须由接受方为其赋值。例如:

 

public static void MyMethod(out int[] arr)

{

   arr = new int[10];   // definite assignment of arr

}

 

与所有的 ref 参数一样,数组类型的 ref 参数必须由调用方明确赋值。因此不需要由接受方明确赋值。可以将数组类型的 ref 参数更改为调用的结果。例如,可以为数组赋以 null 值,或将其初始化为另一个数组。例如:

 

public static void MyMethod(ref int[] arr)

{

   arr = new int[10];   // arr initialized to a different array

}

 

下面的两个示例说明 out 和 ref 在将数组传递给方法上的用法差异。

 

 

 

示例 1

在此例中,在调用方(Main 方法)中声明数组 myArray,并在 FillArray1 方法中初始化此数组。然后将数组元素返回调用方并显示。

 

     public void FillArray1(out int[] myArray)

         {

              // 初始化数组:

              myArray = new int[5] {1, 2, 3, 4, 5};

         }

         //out

         private void button1_Click(object sender, System.EventArgs e)

         {

              int[] myArray; //定义数组

 

              //调用FillArray1并out数组,事先没有初始化

              FillArray1(out myArray);

 

              //显示

              listBox1.Items.Clear();

              for (int i=0; i < myArray.Length; i++)

                   listBox1.Items.Add(myArray[i].ToString());

 

         }

输出

1

2

3

4

5

示例 2

在此例中,在调用方中初始化数组 myArray,并通过使用 ref 参数将其传递给 FillArray2 方法。在 FillArray2 方法中更新某些数组元素。然后将数组元素返回调用方并显示。

 

     public static void FillArray2(ref int[] arr)

         {

              // 如果传递进来的数组初始化为null,则建立一个10个单元空数组:

              if (arr == null)

                   arr = new int[10];

             

              //填入数组数据:

              arr[0] = 123;

              arr[4] = 1024;

         }

 

         //ref

         private void button2_Click(object sender, System.EventArgs e)

         {

              //初始化:

              int[] myArray = {1,2,3,4,5};

              //int[] myArray = null;

        

 

              // ref调用:

              FillArray2(ref myArray);

 

              // 显示数组数据:

              listBox1.Items.Clear();

              for (int i = 0; i < myArray.Length; i++)

                    listBox1.Items.Add(myArray[i].ToString());

 

         }

 

输出

123

2

3

4

1024

 

如果初始化改为:

 

int[] myArray = null;

 

则结果为

 

 

想想为什么呢?

7-5 数组的排序和查找

 

    微软公司经过多年摸索,在.NET平台上大大改进了数组的性能,现在,数组可以排序、搜索元素等,过去编程人员需要花费大量时间进行数组运算的编程,现在可能轻而易举就解决了。

    除数组以外,还有大量的集合类型,放在名称空间的System.Collections中,其中提供的一些类诸如ArrayList、Hashtable都有十分良好的性能。   

    下面分别进行讨论.

 

    a>数组排序

 

    数组排序主要是针对一维数组,下面是实现排序的实例:

 

 

        int[] MyArray1= {3, 6, 1, 0, 5, 7, 8, 2, 9, 4};

          

 listBox1.Items.Clear();

 

            System.Array.Sort(MyArray1);

 

              for (int i=0;i<10;i++)

              {

                   listBox1.Items.Add(MyArray1[i]);

              }

      

 

 

    有时候可以利用另一个数组的值来排序第一个数组,下面的例子是利用

MyArray2的值来排序MyArray1。

 

          int[] MyArray1= {3, 6, 1, 0, 5, 7, 8, 2, 9, 4};

            int[] MyArray2= {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

 

              listBox1.Items.Clear();

 

              System.Array.Sort(MyArray2,MyArray1);

 

              for (int i=0;i<10;i++)

              {

                   listBox1.Items.Add(MyArray1[i]);

             

    这个方法的一个实际的例子,是使一个数组按照字符的多少来排序,请看下面的例子:      

 

 

        string[] MyArray1= {"aa", "cccccc", "vvvv", "s"};

            int[] MyArray2=new int[4];

 

              listBox1.Items.Clear();

 

            for (int i=0;i<4;i++)

             {

                MyArray2[i] = MyArray1[i].Length;

              }

 

            System.Array.Sort(MyArray2, MyArray1);

               

              for (int i=0;i<4;i++)

              {

                   listBox1.Items.Add(MyArray1[i]);

              }

 

 

 

 

    b>数组查找

   

    下面的例子可以理解在树组中如何查找匹配的内容,给出的是数组的索引值。   

 

    使用IndexOf查找不需要数组排序:

 

       string[]  MyArray1= {"aa", "cccccc", "vvvv", "s"};

             int[] MyArray2= {3, 6, 1, 0, 5, 7, 8, 2, 9, 4};

      

             listBox1.Items.Clear();

             listBox1.Items.Add(System.Array.IndexOf(MyArray1, "vvvv"));

             listBox1.Items.Add(System.Array.IndexOf(MyArray2, 5));

 

 

    使用BinarySearch可以在已经排序的数组中快速查找。       

 

       System.Array.Sort(MyArray1);

              for(int i=0;i<4;i++)

              {

                   listBox1.Items.Add(MyArray1[i]);

              }

       

              listBox1.Items.Add(System.Array.BinarySearch(MyArray1, "s"));

结果:

 

本文地址:http://com.8s8s.com/it/it42361.htm