Start-to-Finish Visual Basic 2005:第 1 章 - .NET 入门






4.60/5 (13投票s)
2006 年 10 月 27 日
52分钟阅读

84082
.NET 简介。
|
|
.NET 入门
欢迎来到 .NET!我本来可以说,“欢迎来到太阳系”,因为和太阳系一样,.NET 非常庞大。而且它很复杂。它充满了黑洞和其他一些不总是合乎逻辑的事物。然而(.NET,不是宇宙),它是一个开发软件应用程序的绝佳系统。
.NET Framework 的诞生并非偶然(不像宇宙);微软设计它及其相关的开发语言——尤其是 C# 和 Visual Basic——是为了解决困扰 Windows 软件开发者和用户的各种问题。要完全理解 .NET 的必要性,我们需要对计算机内存进行一次短暂的回顾。
.NET 之前
实用的通用计算机自 20 世纪中叶以来就已存在。然而,对大多数人来说,它们是无法触及的,因为
- 它们花费数百万美元,
- 它们消耗大量电力,
- 维护和编程只能由训练有素的专家进行,而且
- 它们往往与客厅的家具格格不入。
快进大约 30 年。IBM 推出了“个人”计算机。这些“台式”计算机代表了技术上的巨大进步,但只有少数人真正使用过它们。它们仍然很昂贵(数千美元),而且维护和编程仍然需要大量培训投入。IBM PC 放在客厅家具旁边也显得很丑陋。
然后是 Apple Macintosh。凭借其时尚的设计和用户友好的功能,它将计算的乐趣带给了大众。虽然它的编程并不总是直接了当,但它确实带来了不错的结果。难怪比尔·盖茨决定复制——哦,我的意思是改进——它的功能。
Microsoft Windows 1.0 为 IBM/Intel 计算平台带来了更高的可用性。但这对程序员来说并非易事。MS-DOS 开发本已足够困难,再加上 Windows 程序所需的“消息泵”和数百个应用程序编程接口(API)调用。1991 年推出的 Visual Basic 1.0 大大简化了开发过程,但随着 32 位系统、ActiveX 和 COM 组件以及 Web 的出现,即使是 VB 程序员也很快感到不堪重负。
在整个 20 世纪 90 年代,情况似乎只会变得更糟。微软面临来自 Java 语言和 Linux 操作系统的日益激烈的竞争。黑客利用 Windows 平台存在的缓冲区溢出和其他安全问题。用户因冲突的标准、竞争的数据集成技术、注册表膨胀和“DLL 冲突”而经历无数电脑问题。令人沮丧的是,一个 Excel 用户组在雷德蒙德的整个微软园区放火。
好吧,情况并没有那么糟糕。但微软确实看到需要解决其心爱的 Windows 平台上的整体软件开发和可用性问题。它的解决方案是以 .NET Framework 的形式出现的。
回到 .NET 入门
当微软宣布其 .NET 计划时,许多开发者感到惊讶,尤其是 Visual Basic 开发者,他们认为这是“快速应用程序开发”的一大步退后。但 2002 年 .NET Framework 1.0 的发布带来了许多急需的优势。
-
.NET 引入了一个统一的编程环境。所有支持 .NET 的语言在被组装成特定于平台的机器码之前,都会编译成“Microsoft 中间语言”。Visual Basic 和 C# 是围绕这个通用的 .NET“语言”的语言包装器。由于所有支持 .NET 的编译器都使用相同的底层语言,因此它们不再遭受 COM 等其他基于组件的系统中固有的许多数据和语言冲突。Visual Studio 的 .NET 版本还统一了允许程序员编写源代码的标准用户界面。
-
.NET 使开发者转向面向对象技术。.NET 不仅完全拥抱面向对象编程范式,而且 .NET 中的所有内容都包含在对象中:所有数据值、所有源代码块以及所有用户发起的事件的“管道”。一切都出现在对象的上下文中。
-
.NET 简化了 Windows 编程。在 .NET 之前,用 Visual Basic 编程足够容易,直到需要与 API 库之一进行交互时,这在专业编程中经常发生。有了 .NET,这些 API 大多被一系列对象取代,这些对象提供了对许多常用 Windows 功能的访问。由于该层次结构是可扩展的,其他供应商可以添加新功能,而不会破坏现有框架。
-
.NET 增强了安全性。用户和管理员现在可以为不同的 .NET 功能建立安全规则,以限制恶意程序造成的损害。.NET 的“托管”环境还通过强数据类型和垃圾回收等功能解决了缓冲区溢出问题和内存泄漏。
-
.NET 通过标准增强了开发人员的生产力。.NET Framework 基于并使用许多新的和现有的标准,如 XML 和 SOAP。这不仅在 Windows 平台上增强了数据互操作性,还在与其他平台和系统的交互中增强了数据互操作性。
-
.NET 增强了基于 Web 的开发。在 .NET 出现之前,许多基于 Web 的开发都是使用脚本语言完成的。 .NET 将已编译的桌面开发能力带到了 Internet。
-
.NET 简化了应用程序的部署。如果 .NET 已安装在系统上,发布程序就像将其 EXE 文件复制到目标系统一样简单(尽管安装程序更具用户友好性)。侧面部署、ClickOnce 部署(2005 年新增)以及文件版本冲突和“DLL 冲突”(系统中存在同一 DLL 的多个版本,或无法删除某个 DLL 版本)的终结,使得桌面和基于 Web 的部署变得轻而易举。
如果您不理解本节中的某些术语,没关系。您将在后续章节中再次遇到它们,并附有说明。
.NET 对象
要完全理解 .NET 中的软件开发,您必须理解什么是对象。(如果您熟悉面向对象编程—OOP—那么您大概可以跳到下一节,尽管您会错过一些非常精彩的内容。)虽然本节的部分信息也会出现在第 8 章“类和继承”中,但它对于讨论 .NET 至关重要,因此一部分也在此处出现。
对象与数据
从编程角度来看,计算机执行四项基本任务:
-
在计算机的内存区域中存储数据。
-
通过基本操作支持对此数据的处理,包括加法和减法、布尔代数以及文本字符串操作。
-
允许用户与内存中存储的数据进行交互。
-
提供一种方式通过输入和输出设备(如键盘和打印机)以及长期存储介质(如硬盘驱动器)将数据输入和输出内存。
这四项活动的核心是数据。计算机的存在就是为了操作数据。操作系统为此提供了基本基础,但软件应用程序才使这些功能——操作数据的能力——对用户来说变得真实而有意义。高级编程语言是开发这些应用程序的主要工具,每个应用程序都使用一些通用方法来使数据操作功能对程序员可用。回到过去的美好时光,在汇编语言开发时,如果您知道某个数据的内存地址,就可以直接访问和操作它。在 BASIC 的早期版本和大多数其他“过程式”语言中,数据是通过变量访问的。
随着语言的复杂性和目的的增长,它们对数据的看法也随之增长。在 LISP(“List Processing”或“Lots of Irritating Silly Parentheses”的缩写)语言中,任何数据值都存在于一个更大的数据列表或集合中。但在 .NET 语言中,数据是通过对象来查看的。
对象是数据值和相关源代码的集合。而在旧的 BASIC 方言中,每个数据元素都通过其命名的变量或多或少地独立存在,在 OOP 语言中,相关的数据值可以分组到对象中。对象通常包含旨在操作该对象数据值的源代码。
对象通常代表某种事物,通常是具有现实世界对应物的事物,无论是物理的还是概念的。例如,您的代码可能包含一个房屋对象,该对象具有用于地址、外部油漆颜色以及居住在房屋中的人数的字段或属性。相关源代码可以管理这些数据;一个油漆方法可以更改用于外部油漆的颜色值。
对象中的数据和代码元素称为成员。有些成员隐藏在对象内部,只能由对象的源代码访问。其他成员则更公共;您的应用程序中的任何代码都可以使用它们,而不仅仅是对象内部的那部分应用程序代码。考虑一架电视机作为一个对象(参见图 1-1)。
图 1-1 电视机:它是一个对象,而不仅仅是令人反感的。
电视机的公共成员通常易于使用:电源按钮、频道选择器、音量控制等。它们是用户控制电视机数据值(其视频和音频输出)的通道。电视机内部也有隐藏的成员;您可以使用这些成员来影响图像和声音质量,尽管这对大多数用户来说是个坏主意。相信我,您不希望我干扰您电视机的内部成员。同样,一个对象也不希望对象外部的代码干扰其内部成员,除了通过公共成员。我不在乎电视机内部如何工作,只要我能通过使用公开的控件(电源、频道、音量)从它那里获得图像和声音就行。
对象与接口
对象的公共成员代表其接口。如果对象外部的代码想操作该对象的数据,它就使用接口的成员。它不必弄清楚隐藏的成员或它们如何工作,这很好。如果这些内部成员因任何原因发生变化(这种情况比您想象的要频繁),那就更好了。想想过去 30 年电视机的内部结构发生了多大的变化。这是一张我童年时家里电视机的照片。与今天现代的平板电视相比(参见图 1-2)。
图 1-2 那真的是电视机吗?
我家的电视机很酷。它有一个 AM/FM 立体声音响、一个可以播放 33-1/3、45 和 78 RPM 唱片的转盘,以及一个 19 英寸的大显示屏,具有生动的黑白水晶般清晰的显示效果。玩捉迷藏时,可以躲两个孩子在后面。我的朋友有一台相同的型号,他说可以用磁铁在屏幕上画出很酷的永久线条。扬声器面板看起来像垂直的绒毯又有什么关系?这个装置占用了房间 30% 的空间又有什么关系?真空管产生的热量可以用来煎香肠又有什么关系?它不仅仅是一台电视机;它是一个娱乐中心!
现在和右边的那个小巧的平板电视机比比。仔细看,你会发现电视机的接口在过去三十年里基本没怎么变。仍然有电源、音量和频道选择的控件(尽管水平保持和垂直保持不见了,呜呜)。改变的是内部配置。嗡嗡作响的真空管消失了,都被高效的晶体管和固态组件取代了。但这对电视观众来说并没有太大区别,因为公共接口保持不变。
OOP 开发中的对象工作方式相同。只要公共接口保持不变,对象的实际代码和内部数据存储系统——也称为对象的实现——就可以更改,而不会对整个应用程序产生任何影响。
对象与实例
对象接口和实现实际上只代表其设计;这些是通过源代码创建的部分。它们在程序被编译并安装到用户计算机上之前就已存在。事实上,在这个级别上,对象实际上还不被称为对象。在大多数语言(包括 Visual Basic)中,类这个词表示对象接口的实现。
一旦您的应用程序安装在计算机上并启动,代码就会创建类的实例来在内存中存储实际数据。这些实例是 OOP 开发的真正对象。根据您的代码编写方式,单个类实现可能会同时在内存中创建一到数百个对象。
在 .NET 中,您的所有代码和数据值都显示在对象中。您在运行程序中看到的几乎所有内容都是对象:Windows 窗体是对象;窗体上的列表框控件是对象;列表框中的单个项也是对象。
.NET Framework 的组成部分
所以现在您已经了解了对象的所有知识,您可能认为现在是时候把这本书扔到一边,开始编程了。但是还有几个 .NET Framework 的部分需要讨论。这些部分在 .NET 文档中无休止地出现,并且每个部分都有一个三字母缩写(TLA),或者差不多。
通用语言运行时
.NET Framework 的核心是通用语言运行时(CLR),它之所以这样命名,不是因为它普通或常见,而是因为所有支持 .NET 的语言都共同使用它。在 .NET 程序中所做的一切都由 CLR 进行管理。当您创建变量时,感谢 CLR 及其数据管理系统。当您告别一块数据时,感谢 CLR 以及它如何通过其垃圾回收系统管理数据的释放。您是否注意到“管理”一词在这些句子中反复出现?我的编辑肯定注意到了。但“管理”是最恰当的词,因为这正是 CLR 所做的。事实上,为 .NET Framework 编写的软件称为托管代码。任何不受 CLR 控制的代码,包括您的 .NET 应用程序使用的 COM(ActiveX)组件,都称为非托管代码。
CLR 就像洛杉矶国际机场。如果您去过 LAX,您就会知道那里有大量的活动在进行。飞机每分钟都在到达和离开。成千上万的汽车进出双层公路和中央停车场。人们和小偷们在八个主要航站楼和巨大的国际航站楼之间不断穿梭。那里有很多事情在发生,但其中很多都是受管理的。飞机在未经塔台批准的情况下无法起飞或降落。出入口和登机口管理着公路和停车场。友好、礼貌的安保人员管理人流和小偷进出航站楼的安全区域。
LAX 的控制和管理结构确保了人员在飞机和洛杉矶市之间有序而安全地流动。CLR 的控制和管理结构确保了 .NET 代码与计算机其余部分或连接网络之间数据有序而安全地流动。
您可能想知道 CLR 如何处理用任何 .NET 语言(包括 Visual Basic、C# 和 Fortran)编写的程序。微软的竞争对手也想知道。实际上,他们知道,因为没有秘密。所有支持 .NET 的语言都会将您的源代码转换为(即“编译”)Microsoft 中间语言(或MSIL,发音为“missile”,更常用缩写为IL)。对于熟悉汇编语言的人来说,它看起来很像。对于不熟悉汇编语言的人来说,它看起来像一堆乱码。例如,这里有一些 Visual Basic 源代码,用于一个简单的控制台应用程序(非 Windows 文本程序,类似于旧的 MS-DOS 程序),该程序仅从名为“Main”的代码过程中输出“Hello, World!”。
Module Module1
Sub Main()
Console.WriteLine("Hello, World!")
End Sub
End Module
这就是整个 .NET 程序。当 Visual Basic 编译器将其转换为 IL 时,“Main”过程看起来如下(为适应页面稍作修改)。
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.
STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Hello, World!"
IL_0005: call
void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method Module1::Main
是的,它是一堆乱码。但没关系,因为它满足了国际计算机图书协会的要求,即每章第 1 章都必须包含一个“Hello, World”代码示例。另外,CLR 理解它,而这才是 .NET 中真正重要的。只要您能将代码转换为 IL,.NET 就会处理它。Visual Basic 编译器恰好为您生成 IL。其他 .NET 语言编译器,包括 C#,也以 IL 为目标。您甚至可以编写自己的 IL 代码,但您可能读错了这本书。为了让您安心,这将是本书中最后一段 IL 代码。
通用语言规范
声称支持 .NET 的语言不能仅仅因为任何老旧的原因而这么说。它们必须真正与 .NET 及其工作方式兼容。这是通过通用语言规范(CLS)实现的。CLS 定义了语言在被视为 .NET 兼容,或者更准确地说,CLS 兼容之前必须实现的最低功能集。
如果语言愿意,它可以远远超出这个最小值,而且 .NET 包含许多额外的功能,可以在其上构建特定于语言的功能。一个仅实现最低 CLS 指定功能的语言可能无法与超出最低规格的语言组件完全交互。Visual Basic 当然是 CLS 兼容的,事实上它远远超出了这个最小值。
通用类型系统
由于 CLR 无论如何都在控制您的源代码,因此微软认为最好让它也控制源代码的数据。.NET Framework 通过其通用类型系统(CTS)来实现这一点,它定义了 .NET 程序中使用的所有核心数据类型和数据机制。这包括所有数字、字符串和布尔值类型。它还定义了.NET 中核心数据存储单元的对象。
CTS 将所有数据对象分为两类。第一类称为值类型,直接在桶中存储实际数据。如果您有一个 32 位整数值,它会直接放入值类型桶中,供您立即使用。另一个桶包含引用类型。当您查看这个桶时,您会看到一个地图,告诉您在哪里可以找到计算机内存中的实际数据。值类型似乎更容易使用,而且它们确实如此,但它们确实有一些引用类型没有的限制。
使用 CTS 标准编写的程序和组件可以毫无障碍地交换数据。(确实有一些 .NET 数据类型属于“核心”CTS 类型之外,但只有当您想与只能使用核心 CTS 类型的组件进行特定交互时,才需要避免它们。)
当您使用 Visual Basic 编写应用程序时,您的大部分代码将出现在类中。类是包含数据值和相关代码的引用类型。类中包含的数据值通常是核心 CTS 数据类型,但它们也可以包含您在应用程序其他地方设计的对象。Visual Basic 还包含结构,这是类的功能较弱但速度更快的弟弟。结构实现值类型,并且还包含数据和代码。
类和结构只是 Visual Basic 中可用的数据/代码类型中的两种。接口是类和结构的骨架;它们包含了相关类或结构中应出现的设计细节,但不包含任何实际实现或工作代码。委托定义了一个单一的过程(但不是其实现),并用于支持事件,这些事件(由用户、操作系统或您的代码发起)告诉您的代码,“现在开始工作!” 海獭是水生哺乳动物,与鼬鼠有奇怪的亲缘关系,并且喜欢吃海胆。模块是代码和数据块,但与类和结构不同,您不能从中创建独立的对象。枚举将一组相关的整数值分组,通常用作选择列表。
在 .NET 术语中,所有这些术语(类、结构、接口、委托、模块和枚举,但不包括海獭)统称为类型。您可能已经知道 .NET 包含一些令人困惑的元素;如果它很容易,您就不会买一本关于它的书。但是,尽管有所有复杂的技术,这个简单的词“类型”才是导致最多困惑的原因。您很可能会在本本书中每次看到它时都感到痛苦。问题是:它太笼统了。它不仅指通用类型系统中的这些核心元素,而且还在讨论仅 Visual Basic 特定的值类型(更常称为 Visual Basic “数据类型”)时使用。结构的昵称是“用户定义类型”,这是对“类型”的又一个令人困惑的使用。使用 .NET 之前的 Visual Basic 的程序员也记得“Type”是用于创建用户定义类型的语言语句。啊!微软应该使用“类型”以外的词来表示类、接口、枚举等世界。“香蕉”会更好,因为它有时才被用来讨论软件。但“类型”就是这个词,所以您最好习惯看到它。我将在本书中尽可能多地提供上下文。
类型的成员通常由简单的数据字段和代码过程组成,但您也可以包含其他类型作为成员。也就是说,一个类可以包含一个嵌套类,如果它需要的话。只有某些类型支持嵌套(请参阅第 8 章了解详细信息)。我还在那一章讨论了访问级别。每个成员都有一个访问级别,说明哪些代码可以使用该成员。有五个访问级别,从公共(任何人都可以使用该成员)到私有(您必须在类型内部才能知道它的存在)。
第 6 章“数据和数据类型”更详细地讨论了 .NET 类型系统,包括您渴望了解的关于类、结构和其他香蕉的信息。
.NET 类库
计算机实际上非常愚蠢。虽然我能数到 17,但计算机最高只能数到 1;它只认识 0 和 1。CPU 包含一组用于操作 0 和 1 的简单运算符,以及更多用于以复杂方式比较 1 和 0 的运算符。计算机的最后一个绝活是它能够将 0 和 1 移入和移出内存,但又有什么了不起的呢?当然,它以近乎光速执行这些操作,但它能计算 þ 到三百万位小数吗?
好吧,实际上它可以。计算机不了解字母表,它们实际上只能处理 0 和 1,但我现在正在使用计算机写一本获奖书籍。正是能够将简单的单比特数据值和运算符组合成越来越复杂的库,才使得有用的计算机成为可能。1
1. 如果您想阅读一本关于如何从最基本的 0 和 1 的用法中形成复杂的软件和硬件操作的真正引人入胜的书,请阅读 Charles Petzold 的书《Code: The Hidden Language of Computer Hardware and Software》(Microsoft Press,1999)。
.NET Framework 构建于数十年来不断增长的复杂功能之上。当您安装 .NET Framework 时,CLR 及其相关的类型系统代表了框架的核心。仅此一项,框架就包含了让您能够将 2 加 2 并得到 4 的所有基本功能。而且,作为一名业务应用程序开发者,您花了很多时间做这件事。但是,如果您想做更复杂的事情,做一些您知道其他程序员已经做过的事情,比如对名称列表进行排序或在窗体上绘制彩色圆圈?要获得答案,请转到类库,即 .NET 类库。这些与 Framework 一起安装的库包含大量预先编写的(日益复杂)的功能,您不必从头开始编写。
.NET 中有两个类库:基类库(BCL)和框架类库(FCL)。BCL 较小,包含程序必不可少的最基本功能。它只包含如果微软要将框架移植到 Linux 等平台,应用程序绝对不能缺少那些类。
FCL 较大,包含了微软认为您会在程序中想要拥有但 BCL 中不是绝对必需的所有其他内容。不要问 FCL 中有多少类;您不想知道。我打赌微软可能也不知道确切的数字。我确信微软那些疯狂的恶作剧者在 FCL 中加入了一些“恶搞”类,但它们隐藏得很深,以至于很少有程序员会遇到它们。
BCL 和 FCL 中包含成千上万(是的,成千上万!)的类、枚举、接口和其他类型,您可能会认为找到您需要的类很难。但它并不那么难,至少不会非常困难。.NET Framework 包含一个名为命名空间的功能。 .NET 中的所有类型都出现在一个层次结构中——一个树状结构——在根部只有几个最小的条目。层次结构中的每个节点都是一个命名空间。您可以通过命名从根到包含该类的本地命名空间的所有命名空间,并用句点 (.) 分隔每个节点,来唯一地标识库中的任何类或其他类型。
与大多数从单个根节点开始所有分支的层次结构不同,.NET 命名空间层次结构有多个根节点。最大的根命名空间名为System
。它包含许多类,但也包含几个下一级层次结构节点(命名空间)。由于框架包含了 Windows 和 Web 应用程序开发的功能,因此存在包含特定于 Windows 和 Web 的开发功能的命名空间。这些命名空间出现在 System
命名空间内,称为Windows
和Web
。与屏幕上的窗体相关的所有代码都在 Windows
命名空间中,位于 Forms
命名空间中,并且在此命名空间中是实现窗体的实际类,名为Form
。图 1-3 展示了这个命名空间子集的图像。
图 1-3 命名空间和类的层次结构
在 Visual Basic 中,您可以通过用其所有命名空间(从根命名空间开始)限定来标识一个类。Form
类的完全限定名称为
System.Windows.Forms.Form
所有类和类型都存在于层次结构的某个地方,尽管并非所有类都继承自 System
。许多 Visual Basic 特定的支持功能出现在 Microsoft.VisualBasic
命名空间中,该命名空间以“Microsoft”作为其根节点而不是“System”。当您在 Visual Basic 中创建新项目时,默认情况下,项目的名称是层次结构中的一个新顶级节点。如果您创建一个新的 Windows 应用程序,默认的“Form1”窗体具有以下完全限定名称
WindowsApplication1.Form1
这个新应用程序的命名空间不仅仅是 System
命名空间的附属品。它完全集成到完整的 .NET 命名空间层次结构中;WindowsApplication1
命名空间与 System
和 Microsoft
根节点一样,是一个根节点。Visual Basic 包含允许您更改应用程序默认命名空间的功能,或将应用程序的一个类放入特定命名空间。您甚至可以将应用程序的类放在 System
命名空间分支中。将 WindowsApplication1
更改为 System.MySuperApp
会将 Form1
移至
System.MySuperApp.Form1
如果您的应用程序实际上是一个组件或库,用于其他程序,您的应用程序的类将出现在您在其他程序加载您的组件到其应用程序区域时指定的命名空间中。您的代码看起来就像是微软提供的命名空间的一部分。酷不酷?
尽管您可以将类添加到 System
命名空间,但您会招致其他 .NET 程序员的愤怒。System
命名空间应该用于“系统”(即微软提供的)功能,仅此而已。另外,两个供应商可能会使用相同的命名空间路径。因此,为避免潜在的命名空间冲突和其他程序员的白眼,您应该将应用程序的类命名为
CompanyName.ApplicationName.ClassName
单个类或其他类型不能跨越多个命名空间,即使在同一个层次结构分支中。然而,两个类或类型可以在不同的命名空间中共享一个通用名称,即使在同一个分支中。
BCL 和 FCL 的所有类都混合在整个命名空间层次结构中。这意味着您不一定能确定某个特定类来自 BCL 还是 FCL。坦白说,这并不重要;只要类可以在用户工作站上使用,您的代码就不会关心类来自哪个库。
程序集与清单
程序集是 .NET 应用程序或库部分的“部署单元”。在 99.9% 的情况下,程序集就是一个 .NET 可执行文件(“exe”文件)或一个 .NET 类和其他类型的库(“dll”文件)。有可能将一个程序集拆分到多个文件中,但通常是一个文件对应一个程序集。
使一个普通的exe或DLL文件成为程序集的是清单的存在。对于单文件程序集,清单就存在于文件中;它也可以存在于自己的文件中。清单是一块数据,列出了有关程序集的名称、版本信息、默认区域设置、引用外部程序集和类型的信息以及程序集包含的所有文件的列表等重要详细信息。没有清单,CLR 将无法识别程序集,所以请不要丢失它。
程序集可以包含一个可选的强名称。这有助于通过附加到清单的数字签名来确保程序集的完整性和真实性。强名称使用公钥加密来保证程序集的唯一性且未被篡改。Visual Studio 和 .NET Framework 包含可以为程序集添加强名称的工具。
当您部署应用程序时,通常会将所有程序集文件、配置文件以及任何与您的应用程序相关的特定文件放在应用程序的安装目录中,就像 .NET 出现之前的侏罗纪时代一样。为单台机器上的多个应用程序共享而设计的共享程序集可以存储在全局程序集缓存(GAC)中。放置在 GAC 中的所有程序集都必须具有强名称。某些系统可能只允许系统管理员将程序集添加到 GAC。
元数据与特性
程序集是由字母“m”带来的。除了清单和类型成员之外,程序集还包含元数据。存储在程序集中的应用程序代码和数据元素与相关 Visual Basic 源代码中的代码和数据项并行;对于源代码中的每个类型和成员,在已部署的程序集中都有相关的可执行代码。这是有道理的,与 .NET 之前的部署相比并没有太大变化。不同的是,Visual Basic 编译器现在为程序集中的每个类型和成员附加了附加信息——元数据。此元数据记录了相关内容的名称、有关必需数据类型的信息、有关该元素的类继承信息以及用户或其他软件使用该元素之前所需的权限。
您的 Visual Basic 源代码可以通过特性来增强程序集任何元素的元数据。特性生成的元数据不仅仅是一些 ID 号。特性实现了完整的 .NET 类,它们拥有自己的数据值和相关逻辑。任何了解如何处理特性的 .NET 代码都可以检查类型或成员的特性并根据需要采取行动。这包括 Visual Studio、Visual Basic 编译器以及您自己的自定义应用程序。
这里有一个平淡无奇的例子:.NET Framework 包含一个名为 ObsoleteAttribute
的特性。此特性允许您将程序集的类型或成员标记为过时或不再受支持。(Visual Studio 使用此特性在您尝试使用过时的 BCL 或 FCL 功能时显示警告。)要使用该特性,请使用尖括号将其添加到您的应用程序的成员中。
Class MyClassWithOldMembers
<ObsoleteAttribute> Sub DoSomeWork()
End Sub
End Class
此代码定义了一个名为 MyClassWithOldMembers
的单个类,其中包含一个名为 DoSomeWork
的成员过程,该过程显然执行了一些工作。该过程被标记为 ObsoleteAttribute
特性。按照惯例,所有特性的名称都以“Attribute”一词结尾。如果您愿意,可以省略该单词的这部分,只要结果单词不与任何 Visual Basic 语言关键字冲突。
Class MyClassWithOldMembers
<Obsolete> Sub DoSomeWork()
End Sub
End Class
当您编译该类并将其存储在程序集中时,<ObsoleteAttribute>
特性将作为 DoSomeWork
定义的一部分存储。您现在可以编写一个单独的 Visual Basic 应用程序,扫描程序集并输出找到的每个类型和成员的名称和状态。当该分析程序遇到过时的成员时,它会在元数据中检测到 ObsoleteAttribute
,并输出状态
DoSomeWork Procedure: Obsolete, don't use it!
大多数特性都经过精心设计,具有特定目的。一些特性指示 Visual Studio 以特定方式显示类的成员。您可能已经玩过 Visual Studio 的窗体编辑功能来设计一个简单的 Windows 桌面应用程序。当您将控件(如按钮或列表框)添加到窗体并选择该控件时,Visual Studio 允许您通过“属性”面板区域编辑该控件的详细信息(参见图 1-4)。
图 1-4 Visual Studio 中的“属性”面板
Button 控件实现为一个类,其许多类成员出现在“属性”面板中,但并非全部。当 Button 类设计完成后,在其成员中添加了指示 Visual Studio 哪些成员应显示在“属性”面板中,哪些不应显示的特性。Visual Studio 会如实检查这些特性,并仅显示请求的属性。
版本控制
像您一样,我的应用程序从初始发布开始就是完美的,我从不需要修改它们或添加其他功能。但是,有一些软件开发组织——包括一家大公司,为了不引起尴尬,我将仅以其首字母“M”称呼它——觉得有必要通过发布其先前发布的软件产品的“改进”版本来“超越”竞争对手。假设“M”恰好有一个流行的文字处理器,其中包含 1.0 版的拼写检查组件。 “M”还恰好销售一种电子邮件工具,该工具专门依赖于同一共享组件的 1.0 版。如果,“M”在一个竞争激烈的市场中发布了文字处理器和拼写检查组件(现在是 2.0 版)的更新,那么电子邮件工具的拼写检查功能会怎么样?
这并不是说这在现实生活中会发生。但如果发生了,用一个更新但有些不兼容的版本替换一个至关重要的共享组件可能会导致真正的问题。一个相关的问题是在同一工作站上部署同一组件的多个版本,所有版本都在不同的目录中。其中任何一个都可以安全删除吗?
.NET 通过版本控制解决了这些问题。所有使用共享组件的应用程序都精确标识了它们所需的共享组件版本。虽然应用程序可以重新配置以使用更高版本,但默认情况下它只会使用最初指定的共享组件版本。
同一共享组件的多个版本可以添加到 GAC 中,这项功能称为侧面部署。CLR 确保正确的应用程序与正确的组件链接。您甚至可以同时运行使用同一组件不同版本的应用程序。
从源代码到 EXE
现在您几乎了解了 .NET 的所有知识,除了那些讨厌的编程东西。在深入研究实际代码之前,让我们休息一下,然后看看应用程序从头到尾的生命周期(参见图 1-5)。
图 1-5 真实的 Visual Basic 开发过程
所以,以下是步骤:
-
您,作为程序员,负责准备应用程序的基本原料(a)。对于 Visual Basic 程序,这意味着创建了一个或多个扩展名为“.vb”的源代码文件。您的原料还可能包括其他支持文件,如资源文件(文本和图形文件,通常用于多语言支持)。
-
您的应用程序由 Visual Basic 编译器(b)编译。结果是一个程序集,包含清单和元数据。输出实际上是半编译的 IL,并包含原始源代码的类型和成员的就绪执行版本,包括所有成员和类型名称。可以使用 .NET Framework 中包含的工具ildasm.exe(Microsoft 中间语言反汇编器)将所有这些内容“反编译”(还原为完整的 IL,但不是完整的 Visual Basic)。因为您可能不希望任何人反编译您的应用程序并查看代码,所以 Microsoft(和其他第三方)还提供了一个混淆器,它可以充分扰乱您代码的内容,使其足够困难,以阻止窥探。
-
程序集(c)被部署到用户的工作站。有几种不同的方法用于部署应用程序,包括(1)生成标准的 Windows Installer 安装包,(2)生成ClickOnce部署,这是 .NET 2.0 版的新功能,或(3)执行 an xcopy 安装,这仅仅是将 EXE 程序集本身复制到目标机器。无论您选择哪种部署方法,.NET 运行时(d)也必须安装在用户的工作站上。
-
用户会吃——我是说运行——程序(e)。CLR 对 IL 程序集进行最终的即时(JIT)编译,为在本地平台上使用做好准备。然后,它将应用程序呈现给用户,并在应用程序运行时管理应用程序的所有方面。用户体验到的快乐和满足感是使用其他软件应用程序时很少遇到的。
就像准备感恩节大餐一样,实际的开发过程比仅仅阅读关于它的段落(或食谱书)要复杂一些。但它并不难到无法写进一本书里,就像这本书一样。
Visual Studio 和 Visual Basic 怎么样?
等等,Visual Studio 呢?上一节甚至没有提到它。而且它也没有必要,因为您无需使用 Visual Studio 即可开发、编译、部署或运行 Visual Basic 应用程序。.NET Framework 的全部内容——包括 Visual Basic 编译器——都可以在 Microsoft 网站上免费下载;下载并使用它来开发和部署与 Visual Studio 一样强大和复杂的应用程序。
1983 年 7 月的《Datamation》杂志刊登了一封来自读者 Ed Post 的来信,题为“真正的程序员不使用 Pascal”。2我强烈建议您阅读这篇文章,因为它将帮助您快速区分真正的程序员和“乳蛋饼食客”。当您这样做时,请尽快远离真正的程序员。哦,当然,他们可以从混淆的 .NET 程序集中重构您的源代码,但在使用 Visual Studio 的团队项目中,他们将毫无用处。
2. *Datamation*,第 29 卷,第 7 期,1983 年 7 月,第 263–265 页。我还通过搜索标题在互联网上找到了文章的文本。一篇经过少量编辑修改的类似版本的文本也以“真正的程序员不写 Pascal”的名称存在。
一个“真正的程序员”可以使用 Notepad 编写任何 .NET 应用程序,并且可以运行。实际上,他们会使用emacs或vi而不是 Notepad(因为 Windows 不包含打孔卡接口),但结果会是一样的。当您在 Visual Studio 优雅、设计精良且完全可定制和可扩展的用户界面中愉快地输入代码时,他们会咆哮。当您使用 Visual Studio 代码编辑器中内置的 IntelliSense 和自动完成功能时,他们会抱怨并露出沾满奶酪饼干和花生酱的牙齿。当您拖放 Windows 和 Web 用户界面时,他们会再吃一片形状像乳蛋饼的冷披萨。
是的,真正的程序员可以只用文本(或十六进制)编辑器和 .NET 编译器生成完整的应用程序,但您会获得荣耀,因为您将在 FORTRAN 爱好者费力写出他的代码所需时间的一小部分内完成。
Visual Studio 2005
因为这是一本关于 Visual Basic 开发而不是 Visual Studio 使用的书,所以我不会过多深入介绍 Visual Studio 的功能或其用户界面元素。它是一个伟大的应用程序,它与 .NET Framework 的紧密集成使其成为开发 .NET 应用程序的最佳工具。但正如真正的程序员会告诉您的那样,它实际上只是一个经过美化的文本编辑器。Visual Studio 隐藏了 .NET 代码的许多复杂性,并且它自动生成构建应用程序用户界面所需的代码是必备的。它的许多功能都旨在简化向应用程序添加代码的过程。
虽然我在这里不会包含 20 页的 Visual Studio 评论,但您会在文本中找到 Visual Studio 的图像,这些图像被放置在有助于您理解各章讨论的主题。当您第一次启动 Visual Studio 时,它会显示“开始页”。(本书中的屏幕截图取自 Visual Studio 2005 专业版。)
图 1-6 Visual Studio “开始页”
Visual Studio 2005 是该产品自 2002 年 .NET 首次推出以来的第三个主要版本。每个版本(2002 年、2003 年和 2005 年)分别对应 .NET Framework(版本 1.0、1.1 和 2.0)以及 Visual Basic 的 .NET 实现的相关版本。2003 年版本对 Visual Basic 和 Framework 进行了相对较小的更新,但 2005 年版本是一次重大更新。它充满了新的可用性功能,并且有五种美味的版本。
-
Visual Studio 2005 Express Edition。这款入门级产品面向希望学习 .NET 及其核心编程语言之一但不会每天使用它的家庭爱好者和周末程序员。Visual Studio 2005 Express Edition 实际上是多个 Express Edition 语言产品捆绑在一起,包括 Visual Basic 2005 Express Edition(尽管 Visual Basic 2005 Express Edition 也单独提供)。微软的目标是尽可能多地向人们介绍 .NET 编程的乐趣,因此它免费提供 Express Edition。该软件包包含一个简化的类似 Visual Studio 的用户界面,但它对您的程序创建能力施加了一些限制。您仍然可以直接编辑源代码并创建任何复杂度的应用程序,但 Express UI 并不总是会在这方面为您提供帮助。例如,您无法使用 Express 产品开发 Web 应用程序,除非您安装了单独的 Visual Web Developer 产品。此外,Express 不包含太多部署支持;使用 Express Edition 设计的应用程序通常仅限于在您自己的工作站上使用。
-
Visual Studio 2005 Standard Edition。Visual Studio 的 Standard Edition 与 Express Edition 类似,但增加了一些额外功能,例如有关如何使用 BCL 和 FCL 的文档(令人惊讶),以及通过 ClickOnce 部署功能提供的部署支持。它还支持移动设备,如手机和 PDA。
-
Visual Studio 2005 Professional Edition。这是每天以营利为目的开发应用程序的程序员所需的最低级别。这是我使用的版本,它包含了单个程序员进行桌面和基于 Web 的开发所需的所有“强大”功能。僵化的 Express 用户界面已消失,取而代之的是完整的 Visual Studio “强大”集成开发环境(IDE)。但等等,还有更多。您还将获得 SQL Server 2005 Developer Edition。本书中所有与使用开发环境相关的说明都参考专业版。但是,如果您使用 Express 或 Standard Edition 进行操作,您会很好,因为界面非常相似。
-
Visual Studio 2005 Tools for the Microsoft Office System。这个“TOS”版本是专业版,但移除了所有移动设备支持,取而代之的是针对 Microsoft Office 套件的特殊组件。
-
Visual Studio 2005 Team System。Visual Studio 产品线的精华所在是 Team System。它包含了团队共同开发项目的开发团队所需的各项功能,如项目管理工具和源代码控制。Visual Studio 2005 Team Foundation Server(一个单独的产品)可以安装在共享服务器上,并增强了 Team System 套件的功能。
微软正在大力推广其新版 SQL Server——SQL Server 2005。有一个 Express Edition 可供入门级程序员使用;Developer's Edition 包含在 Visual Studio 2005 Professional Edition 及更高版本中。一个特殊的“Everywhere”版本面向移动平台。当然,还有完整的 SQL Server 产品可供全面部署。微软继续支持 Microsoft Access,但它鼓励即使是小型项目也使用 SQL Server,因为它与 .NET 的集成更紧密(从 2005 版本开始)。
除了数据库支持,Visual Studio 2005 还增加了几项新的可用性和功能增强。
-
编辑与继续。这是来自过去的宝藏,自 Visual Basic 1.0 版本以来一直存在,但自 2002 年首次发布 .NET 版以来一直缺席。编辑与继续允许您在 Visual Studio 中运行和调试应用程序时修改 Visual Basic 源代码,并在不重新启动的情况下继续运行修改后的应用程序。“M”公司的程序员肯定为此功能付出了心血,所以请善用它。
-
增强的编译时警告和错误。Visual Studio 始终会标记您代码中的无效语句,但现在它会标记将编译但执行时可能产生意外结果的代码的警告。图 1-7 显示了一个已声明但尚未在代码中使用的变量的警告。
图 1-7 警告
当代码中出现实际的语法错误时,Visual Studio 现在会就如何修复它们提出建议(在许多情况下),并且可以通过单击鼠标按钮来修复它们。在图 1-8 中,单击“错误修正”窗口中的“插入缺失的‘Next’”行将在缺失的“Next”关键字后添加。如果那个小红圈以及它右边的黑箭头看起来很熟悉,那是因为它们来自 Microsoft Office 产品中的智能标签功能。
图 1-8 轻松纠正错误
-
ClickOnce 部署。这种新的 .NET 应用程序分发方法对安装用户提出了更少的要求。例如,ClickOnce 部署在安装和使用应用程序时不需要管理员级别权限。当然,如果用户权限不足,某些功能可能会被禁用。
-
代码片段、项目和项模板以及入门套件。这些功能使将预先编写的代码集成到新项目中更加容易。“代码片段”功能允许您保存一系列简短的代码块,以便快速插入到您的源代码中。如果需要,它们包含填空区域。如果您安装了本书提供的源代码,您将有机会试用项目模板和代码片段,因为示例使用了这些技术。
-
泛型。.NET Framework 和 Visual Basic 都支持泛型,一项在新功能,将在第 16 章“泛型”中讨论。泛型允许您对本来没有这种限制的类强制使用特定的数据类型。
-
运算符重载。Visual Basic 为重载运算符增加了新支持。此功能允许您为标准语言运算符(如加法运算符(+))赋予特殊含义。您开发的代码不仅可以相加数字,还可以相加您自己的复杂类;您定义了“加法”对您的类意味着什么。
-
My。没错:只是“My”。My 是一个新的 Visual Basic 功能,它提供了对通常分散在整个类库中的 FCL 功能的简单集中式访问。您可以在下一章中阅读更多关于它的信息。
尽管有所有这些很棒的新功能,微软仍然拒绝实现最受欢迎的 Visual Studio 功能——“过程自动完成”,在该功能中,Visual Studio 会根据您输入过程名称并使用 Control+Space 组合键来创建源代码过程的全部内容。相反,他们将时间浪费在其他所谓的生产力功能上。有了过程自动完成,您可以在几分钟内编写整个应用程序。在有该功能可用之前,您和我将不得不继续编写软件,精心制作用户期望我们手指编写的优质代码。
摘要
十五年前,Visual Basic 以其拖放式编程模型和华丽的事件驱动开发结构改变了 Windows 开发格局。但自 Windows 3.x 时代以来,Windows 已经发生了很大变化。随着 Windows 的变化,Visual Basic 也随之变化。Visual Basic 2005 通过与 .NET Framework 的关联,提供了用于开发高质量 Windows 桌面、Internet 和下一代移动设备应用程序的编程工具。
微软并没有在 2005 年版本中停止这种进步。下一版 Visual Basic,代号为“Orcas”,有望包含更多高级功能,这些功能将充分利用 Windows Vista 及其 .NET Framework 3.0(以前称为WinFX)编程接口。
项目
欢迎来到“项目”部分,这是每章中您有机会“动手”使用 Visual Studio 2005 和 Visual Basic 的部分。本书的主要项目焦点——库项目——的开发将于第 3 章“项目入门”正式开始,但在此之前仍有一些项目工作要做。在本章中,我将向您介绍本书提供的示例源代码,我们将尝试使用它。
由于大多数项目部分,包括本章,都将涉及 Visual Studio,请确保您已安装并准备好使用它。另外,由于每个项目部分都设计为供您与提供的源代码进行交互式使用,我将假设您已下载并安装了源代码(有关说明,请参阅附录 A“安装软件”),并且正在用一只眼睛阅读本文,同时用另一只眼睛查看源代码。我将在书中打印源代码的各个部分,但由于图书馆项目中有数万行源代码,我无法在此打印每一行。通过简单地阅读它们,您肯定会从每个项目部分中获得很多收益,但如果您可以访问完整源代码,您将获得更多收益。
在本章的项目中,我们将把一个示例程序加载到 Visual Studio 中并运行它。有两种方法可以做到这一点。第一种方法是直接从安装目录打开现有项目。浏览到安装本书源代码的目录,打开“Chapter 1”子目录,然后双击 Chapter1.vbproj 文件。这将直接在 Visual Studio 中打开项目,准备使用。
第二种方法是使用特定于章节的项目模板在 Visual Studio 中创建新项目。本书源代码的安装程序修改了您的 Visual Studio 安装,在新项目对话框窗口中添加了新条目。这些新的“项目模板”中的每一个都可以用作新的 Visual Basic 项目的起点。要使用模板加载第 1 章的示例程序,请启动 Visual Studio。将显示“开始页”,如第 1-6 图所示。从文件菜单中,选择新建项目以显示新建项目对话框(参见图 1-9)。
图 1-9 新建项目对话框—选择真多
您的新建项目对话框可能略有不同,具体取决于您选择安装的 Visual Studio 功能。可用项目按项目类型字段中的描述分组。例如,图 1-9 显示了您可以在 Visual Basic 中创建的各种默认项目类型,包括Windows 应用程序(Windows 平台上的标准桌面应用程序,类库(类定义功能的 DLL)和控制台应用程序(命令行文本应用程序)。要创建新应用程序,首先选择项目类型,然后选择要使用的模板,最后在名称字段中输入新项目的名称。单击确定按钮将创建一个新项目。
要使用第 1 章的示例项目,请在“Visual Basic”项目类型中选择“Start-to-Finish Visual Basic 2005”条目,然后从模板字段中选择“Chapter 1 Sample”(参见图 1-10)。最后,单击确定以创建新示例项目。
图 1-10 选择第 1 章示例项目
项目加载后,通过在解决方案资源管理器中双击 Form1.vb 文件来访问程序的(参见图 1-11)。
图 1-11 示例应用程序的主窗体
Visual Studio Professional Edition 的此默认演示包含三个编辑组件:(1)主编辑区域,其中显示“Form1”视图;(2)解决方案资源管理器面板,提供对项目中所有文件的访问;(3)属性面板,允许您编辑主编辑器区域或其他用户界面元素中当前选定项目的各种方面。
示例项目非常基础。它包含一个带有单个动作按钮的窗体。单击运行应用程序中的此按钮将显示一条简单消息。按 F5 键运行项目。当主窗体出现时,单击继续,点击我按钮将显示图 1-12 中的消息(目标,甜蜜的目标!)。
图 1-12 又见,世界!
那么,我为了开发这个多功能应用程序不得不编写的那些复杂的代码怎么样?它们都在那里供您查看。在解决方案资源管理器面板中,右键单击 Form1.vb 条目,然后从快捷菜单中选择查看代码。(与本书中提供的大多数源代码示例一样,我不得不对代码进行一些小的调整,以便它能在打印页面上正确显示。通常,这涉及将长逻辑行拆分为两个或更多短行。)
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("Hello, World!")
End Sub
End Class
我们将在后面的章节中深入探讨此类代码的细节,但这里是主要内容。
-
主窗体
Form1
在代码中由一个名为Form1
的类表示。 -
窗体包含一个名为
Button1
的命令按钮,该按钮公开一个Click
事件。此事件由Button1_Click
过程处理,该过程是Form1
类的一个成员。 -
“事件处理程序”
Button1_Click
包含一个语句,“MsgBox
”语句。此语句通过向世界显示永远友好的消息框来完成繁重的工作。
这就是我为“Form1.vb”编写的所有代码。它看起来很短,但做了很多工作。肯定还有更多代码隐藏在某个地方。果然,项目中还有大约半打文件。Visual Studio 默认情况下会隐藏这些文件,因为它代表您管理其中部分或全部内容。要查看与 Form1
相关的其他文件,请单击其左侧的加号展开它(参见图 1-13)。
图 1-13 通过解决方案资源管理器查看隐藏文件
双击 Form1.Designer.vb 条目,可以看到 Visual Studio 自动为该窗体编写的代码。(戏剧性的停顿。)哇!看看所有那些可怕的代码。实际上,它并没有那么糟糕。到本书结束时,您将对所有这些内容都有扎实的掌握。在这里第 1 章,理解所有这些内容并不重要,但有几行值得注意。我包含了行号,以便在 Visual Studio 中更容易找到匹配的代码。如果您想在 Visual Studio 中查看行号(此处列出专业版说明)
-
选择工具->选项菜单项以显示 Visual Studio 的选项。
-
从左侧的树形视图中选择文本编辑器 -> Basic -> Editor。如果选中了“显示所有设置”字段,则树形视图中的最后一个组件将是“General”,而不是“Editor”。
-
在右侧选择(勾选)行号字段。
-
单击确定以应用更改。
如果您是 Visual Basic 或 .NET 编程的新手,现在不用担心,如果所有这些代码都无法理解;随着您翻阅本书的页数,一切都会变得清晰。
1 <Global.Microsoft.VisualBasic.CompilerServices. _
DesignerGenerated()> _
2 Partial Public Class Form1
20 <System.Diagnostics.DebuggerNonUserCode()> _
21 Protected Overloads Overrides Sub Dispose _
(ByVal disposing As Boolean)
这些行展示了特性的应用。这两个特性(DesignerGenerated
和 DebuggerNonUserCode
)有点像前面讨论的 Obsolete
特性,因为它们为相关代码提供了某种信息标识。DesignerGenerated
修改了 Form1
代码的整个部分,而 DebuggerNonUserCode
只修改了 Dispose 成员。为了清晰起见,两个特性都包含了它们的完整命名空间路径。DesignerGenerated
特性开头的 Global
关键字实际上是一个 Visual Basic 关键字,意思是“从命名空间层次结构的顶端开始;这不是相对路径。”
2 Partial Public Class Form1
您在第 2 行看到了Partial
这个词?我知道我看到了。嘿,等等;Public Class Form1
也出现在 Form1.vb 文件中,但没有Partial
关键字。Visual Basic 2005 包含一个新功能,允许您通过在至少一个部分中包含 Partial
关键字,将单个类(此处为 Form1
)分成多个源代码文件。很酷吧?它允许 Visual Studio 添加复杂初始化代码到您的窗体(如本 Form1.Designer.vb 文件中的代码),而不会干扰您的主源代码文件(Form1.vb)。
3 Inherits System.Windows.Forms.Form
Inherits
关键字定义了这个新的 Form1
类与先前编写的 System.Windows.Forms.Form
类之间的继承关系。Form
是“基”类,而 Form1
是“派生”类;Form1
继承了 Form
类所有功能,包括其初始外观和感觉。我将在第 8 章详细讨论这些类关系。
44 Friend WithEvents Button1 As System.Windows.Forms.Button
第 44 行定义了出现在窗体中间的Go Ahead, Click Me 按钮。出现在窗体上的所有控件都是类的独立实例。(Friend
是在下一章中描述的一个声明语句。)WithEvents
关键字表示此 Button
类的实例将响应事件,例如用户用鼠标单击它。这一行实际上并没有创建 Button
类的实例;这发生在第 22 行。
22 Me.Button1 = New System.Windows.Forms.Button
New
关键字创建类的实例。在这种情况下,新实例被分配给第 44 行定义的 Button1
类成员。此时,Button1
是 Button
类的默认实例;它没有任何自定义设置,例如大小和位置,或者Go Ahead, Click Me 显示文本。所有这些都在第 27 到 31 行设置。
27 Me.Button1.Location = New System.Drawing.Point(64, 104)
28 Me.Button1.Name = "Button1"
29 Me.Button1.Size = New System.Drawing.Size(152, 23)
30 Me.Button1.TabIndex = 0
31 Me.Button1.Text = "Go Ahead, Click Me!"
最后,按钮在第 38 行“粘”到了窗体上。
38 Me.Controls.Add(Me.Button1)
这会将 Button1
实例添加到 Form1
管理的 Controls
列表。代码中到处使用的 Me
关键字是指 Form1
类本身,因此 Me.Button1
指的是当前 Form1
类中特定的 Button1
类成员。
此文件中的大部分代码都出现在 InitializeComponent
成员过程中。
21 Private Sub InitializeComponent()
...
43 End Sub
当 Visual Basic 创建 Form1
的实例以显示在屏幕上时,它会调用 InitializeComponent
过程来完成将控件添加到窗体的任务。实际上,Visual Basic 会调用窗体的构造函数,而构造函数又会调用 InitializeComponent
。构造函数是特殊的类成员,它们对类实例执行任何所需的初始化。每次创建类实例时,.NET 都会自动调用它们。在 Visual Basic 中,所有构造函数都使用名称 New
,如下面的代码
Friend Class ClassWithConstructor
Public Sub New()
' ----- All initialization code goes here.
End Sub
End Class
我将在第 8 章中更多地讨论构造函数,但现在,请在 Form1
的代码中找到构造函数。(长时间停顿。)什么?没有构造函数?那么,如果没有构造函数,InitializeComponent
成员是如何被调用的?
这就是我想知道的。事实上,当 Visual Basic 编译器为 Form1
生成 IL 代码时,它会悄悄地添加一个构造函数,该构造函数会调用 InitializeComponent
。怎么样!微软为什么不直接将构造函数的代码包含在源代码中呢?这是为了简化程序员的工作。他们需要一个调用 InitializeComponent
的默认构造函数,但又不想在你自己在非设计器文件中添加自己的默认构造函数时产生冲突。因此,他们隐藏了所有代码,直到真正编译窗体的时候才显示出来。显然,这一切都相当保密,所以让我们继续。
好吧,这几乎就是全部代码了,至少是我们现在需要关注的部分。尽管我们很少,甚至可能从不检查 Library 项目中窗体的 Visual Studio 生成的代码,但了解幕后发生的事情还是很有用的。如果你是一名 Visual Basic 6 程序员,你可能曾经用记事本查看过你窗体的源代码。如果你这样做了,你会注意到窗体及其所有控件都是用一系列特殊命令定义的,而不是用实际的 Visual Basic 代码。在 .NET 中,这一切都改变了;窗体及其所有控件都用普通的 Visual Basic 代码创建,所以你可以访问所有内容,并看到真正发生的一切。
现在,请翻到第二章,“Visual Basic 简介”,我将在其中深入探讨 Visual Basic 语言本身。
© Pearson Education 版权所有。保留所有权利。