--
C#编程语言概述
1 C,C++和C#的历史
C#编程语言是在C和C++编程语言的精神上创造出来的。这说明了其拥有强大的功能和简单的学习曲线。但是不能说C#与C和C++相同,因为C#是建立在这两者基础之上的,微软灵活地删除了一些比较繁琐的功能——比如指针。本节将了解C和C++语言,并追踪其演变成C#的历史。
C语言最初目的是为了在UNIX操作系统上使用。它用来创建了许多UNIX应用程序,包括C编译器,并最终用来写UNIX本身。它在学术领域被广泛地接受,包括商业领域,以及软件厂商,如微软和Borland发布了为个人电脑服务的C编译器。原始的Windows API的设计采用C语言来编写Windows代码,而最新的一组核心Windows操作系统的API至今为止仍然保留C编译器。
从设计的角度来看,C缺乏一些细节,其他语言如Smalltalk中已经接受了:一个对象的概念。你将在第8章“编写面向对象的代码”中了解更多关于对象的描述。现在,我们认为一个对象是作为数据的集合,并且可以对数据执行一组操作的。对象类型的编码可以用C来完成,但对象的概念不会强制出现在这个语言中。如果你想构造你的代码,使之类似于一个对象,可以。如果你不想这么做,C也确实不会介意。对象是不是这门语言的固有部分,所以很多人并没有太注意这种编程范式。
面向对象开发的概念开始获得认可后,很明显,C需要细化到去包含这一新的方式。 C++的开发包含了这种改进,它被设计成可以兼容C(比如,所有的C程序也将是C++程序,并可以用C++编译器编译)。C++语言主要是增加了对对象这个新概念的支持。C++语言额外提供了了对类(对象的“模板”)的支持,并启用了一整代的C++程序员去思考它及其行为的使用规范。
C++语言是对C的改进,但它仍然存在一些缺点。 C和C ++是很难得到处理的。不像易于使用的语言,如Visual Basic,C和C ++是非常底层的,并要求你编写大量的编码,来使你的应用程序运行良好。你必须编写自己的代码来处理类似于内存管理和错误检查的问题。C和C++可以实现非常强大的应用程序,但你需要确保你的代码编写得很好,一个漏洞就可以使整个应用程序崩溃或行为异常。由于固定采用C向后兼容C++的设计目标,C++无法打破C的底层特性。
微软设计的C#,保留了很多C和C++的语法。对那些语言熟悉的开发者可以很快地掌握C#。并且尽快地开始代码的编写。对于C#来说,它有一个很大的优势,就是它的设计
--
--
者选择不让它去兼容C和C++。虽然这可能看起来像一个糟糕的处理,但它实际上是一个好消息。C#剔除了一些使得C和C++难以实现的东西。因为所有的C代码也是C++代码,C++必须保留C中所有的原始怪癖和不足。C#中开始用一个纯净的环境,没有任何兼容性的要求,因此可以保留其前辈的长处,并且丢弃使得C和C++程序生存困难的弱点。
2 引入C#
C#这门在.NET Framework中被引进的全新语言,是从C++衍生出来的。然而,C#是一个现代化的,面向对象的(自下而上的)、类型安全的语言。
3 语言特征
下面的章节来看看C#语言的一些特点。如果它们中的某些概念对你来说很陌生,不要担心,所有这些都在后面的章节中详细介绍。
4 类
在C#中的所有代码和数据必须包含在一个类中。你不能在类外定义一个变量,同样的你也不能写任何不在类中的代码。类可以有构造函数,当创建该类的对象时,会自动生成它的析构函数;当类的对象被释放时,类的析构函数也就被销毁了。类支持单继承,并且所有类最终都是从基类调用对象派生出来的。 C#支持各版本的技术,可以保证随着时间的推移,你的类始终保持与使用早期版本时的类代码的兼容性。
下面让我们来看一个叫做Family的类的例子。这个类包含了两个静态域来保存成员的第一个名字和最后一个名字。同时用一个方法来返回成员的全名。
class Class1 {
public string FirstName; public string LastName; public string FullName() { }
return FirstName + LastName; }
注:单继承意味着一个C#类只能从一个基类中继承。
--
--
在C#中,你可以将你的类打包到一个名为namespace的类的集合里面。命名空间有名称,可以在逻辑上帮助类集进行分组。在你开始学习C#时,很明显,有关于.NET Framework所有命名空间都是从系统开始的。微软还选择了包括一些有助于兼容以前代码的类和API的访问通道。这些类都包含在Microsoft命名空间内。
5 数据类型
C#允许你使用两种类型的数据:值类型和引用类型。值类型变量保存实际值。引用类型保存实际的值储存在内存中其他的位置信息。基本类型如字符型,整型,浮点型,以及枚举型和结构体类型,它们都是值类型。而对象和数组类型被处理成了引用类型。C#预定义了引用类型(对象和字符串),同时也预定义了值类型(短字符,短整型,整型,长整型,无符号字符型,无符号短整型,无符号整型,无符号长整型,浮点型,双精度浮点型,布尔型,字符型和十进制类型)。你也可以在代码中定义自己的值类型和引用类型。所有的值类型和引用类型最终都会被一个由基本类型派生出的对象执行。
C#允许将一个类型的值转换为另一种类型的值。你可以使用隐式转换和显式转换来实现。隐式转换总是能成功,并且不会丢失任何信息(例如,你可以转换将一个整型变量隐式转换成一个长整型变量,而不会丢失任何信息,因为长整型变量比整型变量存储的容量大)。显式转换可能会导致你丢失部分数据(例如,将一个长整型变量转换为一个整型变量可能会导致数据丢失,理由同上)。你必须在你的代码中编写转换运算符,来实现显式转换。
6 交叉引用
请参阅第3章,“同变量一起工作”来了解关于隐式转换和显式转换的详细信息。 你可以在C#中使用这一维数组和多维数组。多维数组可以是矩阵,这个阵列和多维数组具有相同的行列数;或者是锯齿状的,其中每个阵列的具有不同的尺寸。
类和结构体可以拥有数据成员,称之为属性和域。域是封装起来的类或结构体相关的变量。你可以定义一个称为Employee的结构体,例如,有一个称为Name的域。如果你定义一个名为CurrentEmployee 的Employee类型的变量,你可以通过编写CurrentEmployee.Name来获取雇员的姓名。属性就像域,但是可以让你编写代码来指定代码访问值时应该发生什么。如果员工的名字必须从数据库中读取,例如,你可以编写代码:“当有人问Name属性的值时,从数据库中读取名字,并且以字符型返回这个值。”
--
--
7 函数
函数是一段可以随时调用的代码,当它被调用时可以有返回值,也可以没有返回值。有一个函数的例子在前面展示过,在本章中,在Family这个类中有函数的例子,Family类中实现显示全名的功能的就是一个函数。函数通常会联合一些返回信息的代码,而方法通常不返回信息。不过对于我们而言,我们一般都会把它们都归结于函数。
函数可以有四种类型的参数:
输入的参数有值传递到函数内,但是函数无法改变它们的值。
输出参数没有任何值,当他们被传递给函数时,函数可以给它们值并且将这个值传回给它的调用者。
引用参数通过引用传递另外的一个值。它们有一个值传递给函数,并且该值可以在函数内部被改变。
参数的参数在列表中定义了一个数组变量。
C#和CLR携手合作,提供自动内存管理。你并不需要编写“为一个整数分配足够的内存”或者“留足够的空间让这个对象使用”这样的代码。CLR监视你的内存使用,并且自动在你需要时自动地取回。同时,当它检测到它不再被使用(这也被称为垃圾收集)时会自动释放内存。
C#提供了大量的运算符,使你能够编写数学运算和移位运算的表达式。它们当中的大量(但并不是所有)运算符可以被重新定义,从而允许你更改这些运算符的作用。
C#允许你在一长串代码中定义不同的执行路径,使用关键字如if,switch, while, for, break和continue,能够使代码根据变量值的不同分入到不同的路径中。
类中可以包含代码和数据。每一个类成员都有一个访问权限,它定义了这个成员对其他对象的可见性。 C#提供了public,protected,internal,protected internal和private这些可接近的范围。
8 变量
变量可以被定义为常量。常量是在你的代码的执行过程中不能被改变值。例如圆周率的值是常量的一个很好的例子,因为它的值不会在你的代码的运行过程中发生改变。枚举类型声明为一组相关的常量指定名称。例如,你可以定义一组枚举类型,使用Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune和Pluto作为它们的值,并且能够在代码中使用这些名字。在代码中使用枚举类型的名字比你使用数字来表示每个行星更具可读性。
--
--
C#提供了用于定义和处理事件的内置机制。如果你写了一个需要执行很长时间的类,你可能需要在操作完成时调用的一个事件来结束这个类。客户可以订阅该事件,并在他们的代码中使用,这使得当你完成你的冗长的操作得到的通知。这个事件处理机制在C#机制使用了委托,这是引用的函数变量。
注:事件处理程序是一个在你的代码中的程序,当一个事件发生时它决定了将会发生什么动作,如用户点击一个按钮来执行的操作。
如果你的类保存了一个值,客户将会想要将你的这个类看成是一个数组来访问这个值。你可以写一段被称为索引的代码,使你的类就像是一个数组一样的被访问。例如,假设你写了一个名为Rainbow的类,类,包含了一组在彩虹中的颜色。访问者可能需要编写MyRainbow [0]检索在彩虹的第一种颜色。你可以在你的Rainbow类中写一个索引,来定义调用者访问你的类时应该返回什么样的内容,就好像它是一个值的数组。
9 接口
C#支持接口,它聚集了属性,方法和阐述一套功能的事件。C#类可以实现接口,它通过接口告诉使用者该类支持的接口中记录的功能集。你可以实现接口而不妨碍任何现有的代码,最大限度地减少兼容性问题的干扰。一旦接口被公开了,它就不能被改变,但它可以通过继承来进化。 C#类可以实现多个接口,虽然这个类只能从一个基类继承。
让我们来看看一个真实的例子,在C#中接口具有非常积极的作用。许多应用程序支持当今的加载项。假设你已经创建了编写应用程序的代码编辑器。这个代码编辑器被执行时,已具有了加载插件的能力。要做到这一点,插件必须遵循一些规则。该DLL加载必须导出一个名为CEEntry的函数,DLL的名称使用CEd作为文件名的开头。当我们运行我们的代码编辑器时,它扫描以CEd开头的所有DLL文件的工作目录。当它找到一个,就将它装载下来;然后它使用GetProcAddress的定位DLL中的CEEntry函数,从而验证了你遵循所有必要的规则来创建一个加载项是必要的。创建并加载加载项的这个方法是非常沉重的负担,因为它负担更多比核查必要的代码编辑器的责任。如果接口是在这种情况下使用的,你的DLL加载项可以运用于一个接口,从而保证所有必要的方法,属性和事件出现在DLL中,并作为文件指定的函数运行。
10 属性
属性声明你的类的CLR的附加信息。在过去,如果你想使你的类自描述,你必须采取断开的方法,其中的文件被存储在外部文件中,如IDL甚至HTML文件。通过你这个开发者的努力,属性解决了这个问题,它在类中约束了任何种类的信息。例如,你可以使用一个属
--