分享

C#基础知识

 仰望//45度微笑 2012-04-09

1       C#基础知识

1.1     简介

C#是一门纯面向对象的新语言,这门语言是专为.NET这个平台开发的。它不仅是语言,也是.NET平台不可缺少的组成部份。C#提高了安全性,同时还支持组件对象模型(COM)和基于Windows的API。C#还允许有限制的使用本机指针。

本章主要探讨C#中的基本编程构造和基本数据类型,简单说说装箱和取消装箱的概念,最后讲下怎样编写和编译简单的C#程序。

1.2     C#程序的基本流程

请研究下面的示例1,这是一个使用C#编写的“Hello World”程序,运行后将会在屏幕上显示出“Hello World”。现在我们来分析这个程序。

示例1:

/*这是我的第一个C#程序*/

using System;

class myFirst

{

public static void Main()

{

Console.WriteLine(“Hello World”);

}

}

第一行:此行为注释,注释以“/*”开头,以“*/”结尾。注释可以包含多个行。

第二行:using System;些行与C/C++中的#include语句非常相似。在这里using是导入指令,System是命名空间。我们可以将命名空间视为一组类,System类是所有类的基类,包含大多数应用程序与操作系统进行交第操作时所需要用到的类。请注意C#每条语句后都有一个“;”号。C#中的所有代码行都必须以分号结尾。

第三行:class myFirst中的class是关键字,代表我们定义了一个类,这个类的名字叫做myFirst。基本语法class<name>{},“{”与“}”之间为类的作用域,为了养成良好的编程习惯,在定义类以后就跟上{},以免忘记。

第五行:public static void Main()函数是C#程序的入口点,我们也称为主函数。即,程序开始执行后首先调用的函数是Main()函数。Public访问修饰符代表此函数声明为公共作用域,因此可以从程序中的任何位置对它进行访问。static为静态成员(稍后章节我们会对它进行详细的讨论),void代表此函数不返回任何值。特别注意C#是严格区分大小写。在此行代码中所有关键字都使用小写字母,只有Main()函数的首字母大写。例如:using与Using是完全不同的。

第七行:这一行为主函数的内容,我们也用{}把它们包含在这个主函数的作用域中,Console.WriteLine(“Hello World”);调用了Console类中的WriteLine方法,并将文本“Hello World”作为参数传递。WriteLine函数将文本显示在控制台或DOS窗口中。请注意:Console是属于System命名空间。如果我们没有导入命名空间,即没有写using System;那么我们将以下列方式实现文本打印。

System.Console.WriteLine(“Hello Word”);

那么我们为什么要预先导入命名空间呢?因为使用完全限定名称表示对象可能很乏味,而且易引发错误。为了减轻这一负担,C#提供了using指令。一个程序中可以导入多个命名空间,但必须在文件头部指定。

以上程序只用于帮助理解C#中的程序执行的基本流程。本章后面的部份将更细的讨论C#。

1.3     C#中的变量声明

C#中的变量声明格式:

AccessModifer DataType VariableName;

AccessModifer:访问修饰符

DataTyep:变量类型

AriableName:变量名

各修饰符的访问级别如表1.1

表1.1:C#的访问修饰符

访问修饰符

描述

Public

使成员可以从任何位置访问

Protected

使成员可以从声明它的类及其派生类内部访问

private

使成员仅可以从声明它的类内部访问

internal

使成员仅可以从声明它的程序集内部访问

 

表1.2:C#数据类型

C#数据类型

描述

Int

声明存储整数值的变量

String

声明存储字符串值的变量。

float

声明存储实数值(包括整数和小数部份)的变量

 

变量命名

示例2:

using System;

class Test

{

static void Main()

{

string @string()

@string=“此例中string是一个关键字,但在本例中作用一个变量名”;

Console.WriteLine(@string);

}

}

注意:上面的示例中声明了一个string类型的变量,因为string是关键字,所以我们在变量前加上前缀@以表示这是一个变量名。

与C#中的变量相关的另一功能是,创建静态变量、类实例变量和数组元素时,会自动为其指定一个默认值。请研究下列示例:

示例3:

using System;

class Test

{

static void Main()

{

int[] array1 = new int[5];

Console.WriteLine (10 * array1[2]);

}

}

以上示例输出为0

表1.3:数据类型及其默认值

类型

默认值

Numeric(int、float、short)

0

bool

False

char

‘\0’

enum

0

引用

null

对于所有其它变量,编译器将引发错误。因此,在编程的时候尽量在使用变量前就为其赋值。

1.4     C#中的基本输入与输出

在执行C#的基本输入和输出的操作时,需要使用System命名空间的Console类的方法。

两个最常用的方法如下所示。

Console.WriteLine()

Console.ReadLine()

示例1中已经使用了Console.WriteLine。但是Console.WriteLine的功能十分强大,可以用它在显示文本之前设置文本的格式。它还带有附加参数、占位符,指定显示方式。

请仔细研究下面的示例4。

示例4:

using System;

class Teest

{

static void Main()

{

int number,result;

number=5;

result=100 * number;

Console.WriteLine(“数字100乘上{0}时,结果为{1}”,number , result);

}

}

示例输出为:数字100乘上5时,结果为500

示例5使用Console.ReadLine()

示例5:

using System

class InputStringTest

{

static void Main()

{

string input;

Console.WriteLine(“请输入数字:”);

input=Console.ReadLine();

Console.WriteLine(“{0}”,input);

}

}

示例5中的ReadLine()方法可读取回车符之前的所有字符。输入将以字符串的形式返回。

1.5     C#中的判断语句

C#中的条件检查与C中相同,可以使用if结构执行条件分支。请记住,C#语法中,条件永远都是boolean值语法如下:

If(expreession)

{

//表达式的结果为true时执行的语句

}

else

{

//表达式的结果为false时执行的语句

}

代码段1:

string str=”条件换算”;

if(str)

{

System.Console.WriteLine(“判断值为True”);

}

if(str = = “条件换算”)

{

System.Console.WriteLine(“判断值为 True”);

}

else

{

System.Console.WriteLine(“判断值为 False”);

}

当编译遇到第一个if语句时,将生成下列错误:

错误CS0029:无法将类型“string” 隐式转换为 “bool”

这个错误的原因是第一个if语句的表达式str的计算结果不是Boolean值。

swich结构的语法如下:

switch(weekday)

{

case 1:

Console.WriteLine(“星期一”);

break;

case 2:

Console.WriteLine(“星期二”);

break;

case 3:

Console.WriteLine(“星期三”);

break;

default:

Console.WriteLine(“默认星期日”);

break;

}

以上语法与C基本想同,只有一个增强功能,它允许将switch结构与字符串一起使用。

1.6     C#中的循环结构(也称迭代结构)

C#提供了下列循环结构类型。

while循环

do循环

for循环

foreach循环

除foreach循环外,其它的所有类型都与C中的相应类型相似。以下为各种循环结构的解释。

while循环

while循环执行一组语句,直至指定的条件为false为止。循环条件要求boolean条件。

语法如下:

while(condition)

{

//语句

}

可在while循环中指定break语句跳出循环。continue语句可用于跳过当前这次循环进入下一次循环。

do循环

do循环与while循环非常相似,不同之处是在while循环中,首先计算条件,然后执行语句,而在do循环中,条件是在循环第一次结束时计算的。在do循环中,至少要执行一次循环才会检查条件。语法如下:

do

{

//语句

}while(condition)

break和continue语句也可以用在do循环中。

for循环

for循环与其它的循环区别不大。循环变量可以作为for语句的一部份进行声明。

语法如下:

for(intialization;condition;increment/decrement)

{

//语句

}

例子:

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

{

Console.WriteLine(i);

}

变量必须是整型

foreach循环

foreach循环是C#中嫁接自VB的概念,该结构常用于能通过集合或数组来循环。

语法如下:

foreach(Type Identifier in expression)

{

//语句

}

请仔细研究下面的示例6:

示例6:

using System;

public class ForEachLoop

{

static void Main (String [] args)

{

int index;

String [] array1=new String [3];

For (index=0;index<3;index++)

{

array1[index]=args[index];

}

foreach (String strName in array1)

{

Console.WriteLine (strName);

}

}

}

输入参数one two ABC得到one two ABC

for循环通过数组args循环,并将其中包含的值指定给数组array1。然后foreach循环通过数组array1循环,并将其中所包含的值一次一个的指定给变量strName。

1.7     C#的构造函数

构造函数是特殊的方法,与包含它们的类同名。创建类实例时,首先执行构造函数。下面是语法。

class MyConstructorEx

{

public MyConstructorEx()

{

//MyConstructorEx构造函数

}

}

C#中的析构函数

C#中的析构函数与构造函数的编写方式相同,它们与类同名,不同之外是有一个颚化(~)符号作为前缀。那么什么时候会执行析构函数呢?在类的实例被删除或超出程序的作用域时,将执行析构函数。

代码段4:

class MyConstructorEx

{

public MyConstructorEx()

{

//MyConstructorEx构造函数

}

public ~MyConstructorEx()

{

//~MyConstructorEx析构函数

}

}

注意:C#中的析构函数虽然与C++中的定义相同,但是行为不同,C#中它们由垃圾回收器调用。垃圾回收器是CLR(.NET运行库)的一种服务。

1.8     C#中数据类型的分类

C#中的数据类型分为两个基本类别,即值类型和引用类型。值类型表示实际数据,存储在堆栈中,而引用类型则表示指向该数据的指针或引用,存储在堆上。Int,char,结构等都是值类型。类、接口、数组和字符串都是引用类型。

Using System;

Class DataTypeTest

{

static void Main()

{

int variableVal=100;

funcTest(variableVal);

Console.WriteLine(variableVal);

}

static void funcTest(int variableVal)

{

int tempVar=10;

variableVal=tempVar * 20;

}

}

输出结果为:100

因为变量variableVal的值在函数funcTest()中被修改后,没有反应到Main()函数。出现这种情况是因为int为值类型,因此当传递至函数funcTest()时,仅传递一个变量的值的副本。

示例8:

using System;

class DataTypeTest

{

public int variableVal;

}

class DataTypeTestRef

{

static void Main()

{

DataTypeTest dataTest=new DataTypeTest();

dataTest.variableVal=100;

funcDataTypeTest(dataTest);

Console.WriteLine(dataTest.variableVal);

}

static void funcDataTypeTest(DataTypeTest dataTest)

{

int tempVar=10;

dataTest.variableVal=tempVar * 20;

}

}

输出结果:200

这是因为这一次传递至函数的参数是一个对象。这个对象属于引用类型,因此传递该对象时,传弟的是对象的引用(也称地址),而不是其值的副本。所在以函数内所做的修改会反应到Main()函数。

表 3.4 数值数据类型和引用数据类型的常见特征

 

值类型

引用类型

变量存储

实际值

引用

保存位置

内联(椎栈)

默认值

Null

传递给函数的参数

值的副本

引用的副本

从3.4表中可以看出:

值类型的变量保存实际值,而引用类型的变量则保存对象的地址。

值类型内存分配在堆栈上,而引用类型的则分配在堆上。

前面部分中曾讲到C#会为变量分配一个默认值。值类型的默认值为零,而引用类型的默认值为null引用。

对值类型执行“=”运算会将值复制至目标变量,而引用类型执行同一运算则会将对像的引用复制至目标。

1.8.1  装箱和取消装箱

简单的说,装箱就是从值类型到引用类型的转换。同样,取消装箱便是从引用类型到值类型的转换。这是C#非常强大的一个功能。可以让你像简单的操作值类型一样操作复杂的引用类型。这对于实现多态性非常重要。

我们来研究下概念,看看代码段5。

代码段5:

class BoxEx

{

int objsTaker(object objectX)

{

//objsTaker接收一个对象

//并在此处对其进行处理

}

object objsConverter()

{

//objsConverter执行处理过程

//并返回对象

}

}

//代码实现

int variable1;

variable1=5;

boxVar.objsTaker(variable1);//第1行

int convertVar=(int)boxVar.objsConverter();//第2行

上面定义了一个包含两个方法的类。第一个方法objsTaker()将一个对象作为其参数。第二个方法variable1的int型值类型变量,并赋值勤5,创建了一个类BoxEx的新对象boxVar。在指定为“第一行”的行中,调用了objsTaker()方法并将variable1作为参数传递。请注意,objsTaker方法使用的一个对象作为其参数。对象是引用类型,而程序中是将值类型的variable1作为参数传弟。通常情况下这样会产生错误,但在C#中,值类型variable1将被隐式转换为引用类型。这个值类型转换为引用类型的过程(无论是隐式还是显式)即称为“装箱”。在接下来的标记为“第2行”的行中,创建了一个新的名为convertVar的int型变量,然后对该变量与objsConverter方法执行相等运算。ObjsConverter()不带参数,但返回一个对象。由于将方法int类型的值类型变量进行了赋值运算,因此必须将此对象显式地转换为int类型(转换是通过将所需的数据类型括到圆括号中来完成的)。这个将引用类型转换为值类型的过程我们称为“取消装箱”。

特别需要注意的是,取消装箱需要进行显式的转换。运行库将执行检查,以确保指定值类型与引用类型中包含的类型匹配。如果此检查失败,将引发异常,而如果该异常没有得到妥善处理,应用程序将终止。

1.9     数据类型处理

C#提供了一个“统一类型系统”。也就是说,C#中的所有数据类型(引用类型或值类型)都是从一个类(object类)派生而来的。这意味着,C#中的一切全都是对象(因为所有类型都是object类的派生物)。

下面我们来阐释这一点。

示例9:

using System;

class ObjectProff

{

static void Main()

{

string objectVal;

objectVal=7.ToString();

Console.WriteLine(“该值现在是”+objectVal);

}

}

此示例输出结果是:该值现在是7

请注意粗体显示部份,7是一个数字,如果是一个字符串,那么我们应该用双引号把它引起来。这里没引,说明一个整型。为何数字可以拥有方法。在C#,一切都是对象,即便是数字7也被认为是对象。因此,它可以拥有方法,而ToString()就是方法之一。此方法是将数字7转换为字符串值。

C#的另一个激动人心的功能:由于所有类型都是由共同的一个类,object 类派生而来,因此他们具有一些相同的特征。

1.10        C#中的静态成员

某此情况下,需要在类中定义这样的成员:这些成员不与任何其他特定对象相关联(类本身除外)。也就是说,无论有多少该类的对象,只会有此方法/字段的一个实例。在C#中可以使用关键字static定义静态成员,如下代码所示:

代码段6:

static int staticMem;

static int instanceCount()

{

        //instanceCount实现

}

1.11        数组

数组是一组具有类似数据类型的值。这些值存储在相邻的内存位置,因此访问和操纵这些值更为简便。数组下标由零开始,C#中的数组属于引用类型,因此存储在堆中。语法如下:

        DataTyep[number of elements] variableName;

下面的代码段显示了一个数组声明示例。

代码段7:

int[6] array1

此示例声明了一个名为array1的整型类型数组,该数组包含6个元素。

代码段8:

string[] array2;

array2 = new string[5];

该示例表明,数组中元素的个数可在程序中稍后部份指定。

代码段9:

string[] array3 = {“top”, “down”,“left”,“right” };

该示例表明,可以在声明阶段进行数组初始化。

1.12        结构

可以使用类来实现对象。但某些情况下,可能需要使对象具有内置数据类型的行为,以加快分配,避免过多重载和引用开销。这个问题可以通过使用结构来解决。结构与类很相似,都表示可以包含数据成员和函数成员的数据结构。与类不同的是,结构是值类型并且不需要堆分配。结构类型的变量直接包含结构结构的数据,而类类型的变量包含对数据的引用(该变量称为对象)。C#的结构内可以定义方法,并且还可以有一个构造函数。

类与结构有很多相似之处:结构可以实现接口,并且可以具有与类相同的成员类型。然而,结构在几个重要方面不同于类:结构为值类型而不是引用类型,并且结构不支持继承。结构的值存储在“在堆栈上”或“内联”。

下面我们来研究一下下面的代码段:

代码段10:

struct structEx

{

        public int structDataMember;

        public void structEx()

        {

                //构造函数实现

}

public void structMethod1()

{

        //structMethod1实现

}

}

上面代码段所示,名为structEr的结构中有一个构造函数、一个方法和一个数据成员。结构也有自己的局限性,它们不能像类那样实现继承。更为重要的是,结构是值类型,而类则是引有类型。在C#中,值类型实际是属于System命名空间的结构。例如:long类型是System.Int64结构的别名。也就是说,使用简单类型时,实际上是在使用基类中的结构。

例如,将 Point 定义为结构而不是类在运行时可以节省很多内存空间。下面的程序创建并初始化一个 100 点的数组。对于作为类实现的 Point,出现了 101 个实例对象,因为数组需要一个,它的 100 个元素每个都需要一个。

class Point

{

   public int x, y;

   public Point(int x, int y) 

{

      this.x = x;

      this.y = y;

   }

}

class Test

{

   static void Main() 

{

      Point[] points = new Point[100];

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

         points = new Point(i, i*i);

   }

}

如果将 Point 改为作为结构实现,如

struct Point

{

   public int x, y;

   public Point(int x, int y) 

{

      this.x = x;

      this.y = y;

   }

}

则只出现一个实例对象(用于数组的对象)。Point 实例在数组中内联分配。此优化可能会被误用。使用结构而不是类还会使应用程序运行得更慢或占用更多的内存,因为将结构实例作为值参数传递会导致创建结构的副本。

1.13        枚举类型

枚举类型是声明一组命名常数的独特类型。当程序中某些数值可以具有一组特定值时,可以使用枚举类型。假设需要使程序仅接受五个值,例如:Monday、Tuesday、Wednesday、Thursday和Friday作为Weekdays的值。要强制实现此要求,仅需要指定包含指定值的枚举类型Weekdays,并编写一个仅接受此枚举数作为参数的方法。下段的代码段对此进行了说明。

代码段11:

public class Holiday

{

        public enum WeekDays

        {

Monday,

Tuesday,

Wednesday,

Thursday,

Friday

}

public void GetWeekDays (String EmpName,WeekDays DayOff)

{

        //处理WeekDays

        …

}

static void Main()

{

        Holiday myHoliday = new Holiday();

        MyHoliday.GetWeekDays(“Richie”,Holiday.WeekDays.Wednesday);

}

}

与C一样,C#中的枚举数拥有与值关联的数字。默认情况下,向枚举数的第一个元素赋值0,而其后各个元素的值较前一个元素的值都递增1。不过这些值可以重写,并且可以在初始化阶段指定其他的值。

代码段12:

public enum WeekDays

{

        Monday=1,

        Tuesday=2,

        Wednesday=3,

        Thursday=4,

        Friday=5

}

1.14        编译和执行C#程序

首先要运行C#程序必须要有C#运行的环境。即安装Microsoft .NET Framework SDK v1.1或以上版本。

csc.exe是.net用来编译.cs文件的,但必须要在安装目录下使用。 所以我们要设置一下环境变量。 

C#环境变量设置: 

1、在桌面右击[我的电脑]->[属性]->[高级]->[环境变量] 

2、在下面的系统变量栏点击“新建” 

3、变量名输入“csc” 

4、变量值输入:“C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\” (2000是C:\WINNT\Microsoft.NET\Framework\v1.1.4322\)

5、然后在系统变量列表框中双击“Path” 

6、在变量名文本框的最后面加入 ; “%csc%” 

恩,现在可以在任意目录下调试.cs文件了。

下面给出命令行示例

编译 File.cs 以产生 File.exe: 

csc File.cs 

编译 File.cs 以产生 File.dll: 

csc /target:library File.cs 

编译 File.cs 并创建 My.exe: 

csc /out:My.exe File.cs 

通过使用优化和定义 DEBUG 符号,编译当前目录中所有的 C# 文件。输出为 File2.exe: 

csc /define:DEBUG /optimize /out:File2.exe *.cs 

编译当前目录中所有的 C# 文件,以产生 File2.dll 的调试版本。不显示任何徽标和警告: 

csc /target:library /out:File2.dll /warn:0 /nologo /debug *.cs 

将当前目录中所有的 C# 文件编译为 Something.xyz(一个 DLL): 

csc /target:library /out:Something.xyz *.cs 

编译 File.cs 以产生 File.dll: csc /target:library File.cs这个就是我们使用最多的一个命令,其实可以简单的写成csc /t:library 

File.cs,另外的一个写法是 

csc /out:mycodebehind.dll /t:library mycodebehind.cs,这个可以自己指定输出的文件名。 

csc /out:mycodebehind.dll /t:library mycodebehind.cs mycodebehind2.cs,这个的作用是把两个cs文件装到一个.dll文件里,很有用哦。

1.15        小结

C#变量的声明方式如下:

AccessModifier DataType VariableName;

C#中,通过添加前缀@符号,可以将关键字用作变量名称。此@符号不是标识符的一部份。

在C#,静态变量、类实例变量和数组元素在创建时自动赋值。

选择语句可用于根据表达式的值执行各种操作。

C#中的swhitch语句要求为每个case块都使用一个break语句。

C# 允许将switch结构与字符串一起使用。

C# 提供了下列循环结构类型:

while循环

do循环

for循环

foreach循环

在C#中,数据类型分为两种基本类型,即值类型和引用类型。

在C#中,多数基本数据类型(如 int、char),包括结构在内,为值类型。引用类型包括类、接口、数组和字符串。

装箱是指从值类型到引用类型的转换,而取消装箱是指从引用类型到值类型的转换。

C#中的所有数据类型都是从一个类即object类派生而来的。

C#结构内部可以定义方法,也可以拥有构造函数。

枚举类型是声明一组命名常数的独特类型。

1.16        练习

1. C#中的标识符可以是保留关建了。

a.对 b.错

2. ___________方法用于接受用户输入。

a.Console.Read b.Console.RealdLine

c.Console.WriteLine

3. 在C#中,if结构始终要求条件的计算结果为boolean类型。

a.对 b.错

4. 值类型存储于____________________。

a.堆栈 b.堆

c.队列

5. 与C/C++不同,C#允许结构拥有____________。

a.仅构造函数 b.方法和构造函数

1.17        作业

编写C#程序,实现下列目的:

1. 显示一条消息,要求用户输入自己的姓名、雇员编号和部门。接受输入的值并显示在屏幕上。(提示:使用多个变量存储这些值。)

2. 修改上面的程序,以下列方式显示这些值。如果输入的值为Samuel、7576和HR,则输出应为:HR部门的Samuel的雇员编号为7576。

3. 在上述程序中,接受用户输入的值作为命令行参数。对命令行参数编号并将其显示在屏幕上。

假如,假设用户在<Filename>中输入:Samuel 7576 HR

则输出应为

1:Samuel

2:7576

3:HR

4. 在屏幕上显示下面的项列表:

1. 加

2. 减

3. 乘

4. 除

接受用户提供的三个integer值。前两个integer值为数字,按照用户的选择对其进行数学运算,第三个integer值为用户要执行的数学运算。此值不能小于1且不能大于4。根据用户的选择(用户提供的第三个interger值)执行下列运算。

如果此值为 则执行

加 将前两个integer值相加,并显示结果

减 从第一个integer值减去第二个integer值,并显示结果

乘 将前两个integer值相乘,并显示结果

除 用第二个integer除第一个integer,并显示结果

提示:使用switch结构或多个if 语句

5. 编写一个结构,以华氏和摄氏的形式存储温度。编写一个函数,转换温度表示形式,如从华氏温度转换为摄氏温度。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多