一. 公共语言运行库(CLR)
——————————————————————————————————————————————————————
1.3.4
通过异常处理错误
.NET Framework
可以根据异常使用相同的机制处理错误情况
.NET
提供了一种基础结构,让面向
.NET
的编译器支持异常处理。特别是它提供了一组
.NET
类来表示异常,
——————————————————————————————————————————————————————
1.3.5
特性的使用
特性
(attribute)
是使用
C++
编写
COM
组件的开发人员很熟悉的一个功能
(
在
Microsoft
的
COM
接口定义语言
(Interface Definition Language
,
IDL)
中使用特性
)
。特性最初是为了在程序中提供与某些项相关的额外信息,以供编译器使用。
.NET
支持特性,因此现在
C++
、
C#
和
Visual Basic 2008
也支持特性。但在
.NET
中,对特性的革新是建立了一个机制,通过该机制可以在源代码中定义自己的特性。这些用户定义的特性将和对应数据类型或方法的元数据放在一起,这对于文档说明书十分有用,它们和反射技术一起使用,以根据特性执行编程任务。另外,与
.NET
的语言无关性的基本原理一样,特性也可以在一种语言的源代码中定义,而被用另一种语言编写的代码读取。
——————————————————————————————————————————————————————
程序集
(assembly)
是包含编译好的、面向
.NET Framework
的代码的逻辑单元。
程序集的一个重要特性 是它们包含的元数据描述了对应代码中定义的类型和方法。程序集也包含描述程序集本身的元数据,这种程序集元数据包含在一个称为
"
程序集清单
"
的区域中,可以检查程序集的版本及其完整性。
ildasm
是一个基于
Windows
的实用程序,可以用于检查程序集的内容,包括程序集清单和元数据。第
17
章将介绍
ildasm
。
有了程序集后,因为所有的元数据都与程序的可执行指令存储在一起。注意,即使程序集存储在几个文件中,数据也不会出现不同步的问题。这是因为包含程序集入口的文件也存储了其他文件的细节、散列和内容,如果一个文件被替换,或者被塞满,系统肯定会检测出来,并拒绝加载程序集。
程序集有两种类型:共享程序集和私有程序集。
——————————————————————————————————————————————————————
私有程序集是
最简单
的一种
程序集类型
。私有程序集一般
附带
在某个软件上,且
只能用于
该软件。附带私有程序集的常见情况是,以可执行文件或许多库的方式提供应用程序,这些库包含的代码只能用于该应用程序。
因为私有程序集完全是自含式 的,所以安装它的过程就很简单。只需把相应的文件放在文件系统的对应文件夹中即可
(
不需要注册表项
)
,这个过程称为
"0
影响
(xcopy)
安装
"
。
——————————————————————————————————————————————————————
共享程序集是其他应用程序可以使用的
公共库
。因为其他软件可以访问共享程序集,所以需要采取一定的保护措施来防止以下风险:
·
名称冲突 ,另一个公司的共享程序集执行的类型与自己的共享程序集中的类型同名。因为客户机代码理论上可以同时访问这些程序集,所以这是一个严重的问题。
为了避免名称冲突,共享程序集应根据私钥加密法指定一个名称
(
私有程序集只需要指定与其主文件名相同的名称即可
)
。该名称称为强名
(strong name)
,并保证其唯一性,它必须由要引用共享程序集的应用程序来引用。
·
程序集被同一个程序集的不同版本覆盖
--
新版本与某些已有的客户机代码不兼容。
这些问题的解决方法是把共享程序集放在文件系统的一个特定的子目录树中,称为全局程序集高速缓存
(GAC)
。
与覆盖程序集相关的问题,可以通过在程序集清单中指定版本信息来解决,也可以通过同时安装来解决。
——————————————————————————————————————————————————————
因为程序集存储了元数据,包括在程序集中定义的所有类型和这些类型的成员的细节,所以可以 编程访问这些 元数据。这个技术称为反射,第
13
章详细介绍了它们。该技术很有趣,因为它表示托管代码实际上可以检查其他托管代码,甚至检查它自己,以确定该代码的信息。它们常常用于获取特性的详细信息,也可以把反射用于其他目的,例如作为实例化类或调用方法的一种间接方式,如果把方法上的 类名指定为字符串,就可以选择类来实例化方法,以便在 运行时调用,而不是在编译时调用,例如根据用户的输入来调用
(
动态绑定
)
。
——————————————————————————————————————————————————————
.NET
基类是一个内容 丰富的托管代码类集合 ,它可以完成以前要通过
Windows API
来完成的绝大多数任务。这些类派生自与中间语言相同的对象模型,也基于单一继承性。无论
.NET
基类是否合适,都可以实例化对象,也可以从它们派生自己的类。
WinCV
是一个基于
Windows
的实用程序,可以用于浏览基类库中的类、结构、接口和枚举。本书将在第
15
章介绍
WinCV
。
——————————————————————————————————————————————————————
命名空间是
.NET
避免类名冲突 的一种方式。
如果没有显式提供命名空间,类型就添加到一个没有名称的全局命名空间中。
Microsoft
建议 在大多数情况下,都至少要提供 两个嵌套的命名空间名,第一个是公司名,第二个是技术名称或软件包的名称,而类是其中的一个成员,例如
YourCompanyName.Sales Services.Customer
。在大多数情况下,这么做可以保证类的名称不会与其他组织编写的类名冲突。
——————————————————————————————————————————————————————
1.7 用C#创建 .NET应用程序
C#
可以用于创建控制台应用程序
——————————————————————————————————————————————————————
ASP
是用于创建带有动态内容 的
Web
页面的一种
Microsoft
技术。
ASP
也有缺点。
服务器端代码是 解释性的,
ASP
文件很难维护 ,不是结构化的,
ASP
有时开发起来困难,因为它 不支持错误处理和类型检查。
1. ASP.NET
的特性
ASP.NET
页面是结构化。每个页面继承
System.Web.UI. Page
类,可以重写在
Page
对象的生存期中调用的一系列方法
。因为可以把一个页面的功能放在有明确含义的事件处理程序中,所以
ASP.NET
比较容易理解。
最清楚的是,
ASP.NET
的后台编码功能允许 进一步采用 结构化的方式。
ASP.NET
允许把页面的服务器端功能 单独放在一个类中,把该类 编译为
DLL
,并把该
DLL
放在
H-TML
部分下面的一个目录中。放在页面顶部的后台编码指令将把该文件与其
DLL
关联起来。当浏览器请求该页面时,
Web
服务器就会在页面的后台
DLL
中引发类中的事件。
最后,
ASP.NET
在性能的提高上非常明显。传统的
ASP
页面是和每个页面请求一起解释,而
Web
服务器是在编译后高速缓存
ASP.NET
页面。这表示以后对
ASP.NET
页面的请求就比
ASP
页面第一次执行的速度快得多。
ASP.NET
还易于编写通过浏览器显示窗体的页面,这在内联网环境中会使用。传统的方式是基于窗体的应用程序提供一个功能丰富的用户界面,但较难维护,因为它们运行在非常多的不同机器上。因此,当用户界面是必不可少的,并可以为用户提供扩展支持时,人们就会依赖基于窗体的应用程序。
2. Web
窗体
为了简化
Web
页面的结构,
Visual Studio 2008
提供了
Web
窗体。它们允许以创建
Visual Basic 6
或
C++ Builder
窗口的方式图形化地建立
ASP.NET
页面;换言之,就是把控件从 工具箱拖放到窗体上,再考虑窗体的代码,为控件编写事件处理程序。在使用
C#
创建
Web
窗体时,就是创建一个 继承自
Page
基类 的
C#
类,以及把这个类看作是后台编码的
ASP.NET
页面。当然不必使用
C#
创建
Web
窗体,而可以使用
Visual Basic 2008
或另一种
.NET
语言来创建。
3. Web
服务器控件
用于添加到
Web
窗体上的控件与
ActiveX
控件并不是同一种控件,它们是
ASP.NET
命名空间中的
XML
标记 ,当请求一个页面时,
Web
浏览器会动态地把它们转换为
HTML
和客户端脚本。
Web
服务器能以 不同的方式显示相同的服务器端控件,产生一个对应于请求者特定
Web
浏览器的转换 。这意味着现在很容易为
Web
页面编写相当复杂的用户界面,而不必担心如何确保页面运行在可用的任何浏览器上,因为
Web
窗体会完成这些任务。
可以使用
C#
或
VisualBasic2008
扩展
Web
窗体工具箱。创建一个新服务器端控件,仅是执行
.NET
的
System.Web.UI.WebControls.WebControl
类而已。
4. XML Web
服务
目前,
HTML
页面解决了
World Wide Web
上的大部分通信问题 。有了
XML
,计算机就可以用一种 独立于设备的格式,在
Web
上彼此通信。将来,计算机可以使用
Web
和
XML
交流信息,而不是专用的线路和专用的格式,例如
EDI (Electronic Data Interchange)
。
XML Web
服务是为面向
Web
的服务而设计的,即远程计算机彼此提供可以分析和重新格式化的动态信息,最后显示给用户。
XML Web
服务是计算机给
Web
上的其他计算机以
XML
格式显示信息的一种便利方式。
在技术上,
.NET
上的
XML Web
服务是给请求的客户返回
XML
而不是
HTML
的
ASP.NET
页面。这种页面有后台编码的
DLL
,它包含了派生自
WebService
类的类。
Visual Studio 2008 IDE
提供的引擎简化了
Web
服务的开发。
公司选择使用
XML Web
服务主要有两个原因。第一是因为它们 依赖于
HTTP
,而
XML Web
服务可以把现有的网络
(HTTP)
用作传输信息的媒介。第二是因为
XML Web
服务使用
XML
,该数据格式是自我描述的、非专用的、独立于平台的。
——————————————————————————————————————————————————————
1.7.3 使用Windows Presentation Foundation(WPF)
有一种最新的技术叫做
Windows Presentation Foundation(WPF)
。
WPF
在建立应用程序时使用
XAML
。
XAML
表示可扩展的应用程序标记语言
(Extensible Application Markup Language)
。
XAML
是用于创建窗
XML
声明,它代表
WPF
应用程序的所有可视化部分和操作。虽然可以编程利用
WPF
应用程序,但
WPF
是迈向 声明性编程的一步,而声明性编程是编程业的 趋势。声明性编程是指,不是利用编译语言,如
C#
、
VB
或
Java
,通过编程来创建对象,而是通过
XML
类型的编程来声明所有的元素。
——————————————————————————————————————————————————————
1.7.6 Windows Communication Foundation(WCF)
通过基于
Microsoft
的技术,可以采用许多方式将 数据和服务从一处 移动到另一处。例如,可以使用
ASP.NET Web
服务、
.NET Remoting
、
Enterprise Services
和用于初学者的
MSMQ
。应采用哪种技术?这要考虑具体要达到的目标,因为每种技术都适合于不同的场合。
因此,
Microsoft
把所有这些技术集成在一起,放在
.NET Framework 3.0
和
3.5
中。现在只有一种移动数据的方式
-- Windows Communication Foundation(WCF)
。
WCF
允许建立好服务后,只要修改配置文件,就可以用多种方式提供该服务
(
甚至在不同的协议下
)
。
WCF
是一种连接各种系统的强大的新方式。
——————————————————————————————————————————————————————
2.8.2
命名空间的别名
using alias = NamespaceName;
alias::NamespaceExample NSE = new alias::NamespaceExample();
注意命名空间别名的 修饰符是
::
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
3.8 扩展方法
有许多方法扩展类。如果有类的源代码,继承(如第
4
章所述)就是给对象添加功能的好方法。但如果没有源代码,该怎么办?此时可以使用扩展方法,它允许改变一个类,但不需要类的源代码。
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
7.1 委托
当要把方法 传送给其他方法 时,需要使用委托。
·
事件
--
一般是通知代码发生了什么事件。
GUI
编程主要是处理事件。在发生事件时,运行库需要知道应执行哪个方法。这就需要把 处理事件 的方法传送为委托 的一个参数 。这些将在本章后面讨论。
在
C
和
C++
中,只能提取函数的地址,并传送为一个参数。
C
是没有类型安全性的。可以把任何函数传送给需要函数指针的方法。这种直接的方法会导致一些问题,例如类型的安全性,在进行面向对象编程时,方法很少是孤立存在的,在调用前,通常需要与类实例相关联。而这种方法并没有考虑到这个问题。所以
.NET Framework
在语法上不允许使用这种直接的方法。如果要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊的对象类型,其特殊之处在于,我们以前定义的所有对象都包含数据,而 委托包含的只是 方法的地址。
——————————————————————————————————————————————————————
理解委托的一个要点是它们的类型 安全性非常高。在定义委托时,必须给出它所代表的方法 签名和返回类型 等全部细节。
理解委托的一种好方式是把委托当作给方法签名和返回类型指定名称。
委托实现为派生自基类
System. Multicast Delegate
的类,
System.MulticastDelegate
又派生自基类
System.Delegate
。
给定委托的实例可以表示任何类型的 任何对象上的 实例方法或 静态方法
--
只要方法的签名匹配于委托的签名即可。
——————————————————————————————————————————————————————
7.1.6
匿名方法
到目前为止,要想使委托工作,方法必须已经存在
(
即委托是用方法的签名定义的
)
。但使用委托还有另外一种方式:即通过匿名方法。匿名方法是用作委托参数的一个代码块。
用匿名方法定义委托的语法与前面的定义并没有区别。但在实例化委托时,就有区别了。
——————————————————————————————————————————————————————
事件接收器是指在发生某些事情时被通知的任何应用程序、对象或组件。当然,有事件接收器,就有事件发送器。发送器的作用是 引发事件。发送器可以是应用程序中的另一个对象或程序集,在系统事件中,例如鼠标单击或键盘按键, 发送器就是
.NET
运行库。注意,事件的发送器并不知道接收器是谁。这就使事件非常有用。
现在,在事件接收器的某个地方有一个方法,它负责处理事件。在每次发生已注册的事件时,就执行这个事件处理程序。此时就要使用委托了。由于发送器对接收器一无所知,所以无法设置两者之间的引用类型,而是使用委托作为中介。发送器定义接收器要使用的委托,接收器将事件处理程序注册到事件中。连接事件处理程序的过程称为封装事件。封装
Click
事件的简单例子有助于说明这个过程。
public delegate void EventHandler(object sender, EventArgs e); //注意这个,这是事件委托
public Form1()
{
InitializeComponent();
buttonOne.Click += new EventHandler(Button_Click);
}
在
Visual Studio
中,注意在输入
+=
运算符之后,就只需按下
Tab
键两次,编辑器就会完成剩余的输入工作。在大多数情况下这很不错。但在这个例子中,不使用默认的处理程序名,所以应自己输入文本。
System.Windows.Forms.Button, Text: button1(这个是sender的内容)
我们已经学习了许多概念,但要在接收器中编写的 代码量是很小 的。记住,编写事件接收器常常比编写事件发送器要 频繁得多。至少在
Windows
用户界面上,
Microsoft
已经编写了所有需要的事件发送器
(
它们都在
.NET
基类中,在
Windows.Forms
命名空间中
)
。
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————
——————————————————————————————————————————————————————