孙健NET软件工程师培训课程_第1页
孙健NET软件工程师培训课程_第2页
孙健NET软件工程师培训课程_第3页
孙健NET软件工程师培训课程_第4页
孙健NET软件工程师培训课程_第5页
已阅读5页,还剩186页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1:VS.NET的开发环境1:Windows2000Professional,Windows2000Server,Windows2000AdvancedServer,WindowsXP.NetFramework(以前叫NGWS)

IE5.5

以上2:调试技巧这个我们将会在后面在给大家提到,会在具体的项目里给大家实现,在这里将不在说了.第一章

第一节:VS.NET介绍12:部署配置1:如何发布部署?--首先做好一个项目,在检查调试无错误的情况下选择工具菜单下的生成发布网站,如图所示:选择你要保存的路径,单击确定就可以了。23:如何安装IIS?打开控制面板添加删除程序添加删除windows组件。如图:如果你的IIS是安装过的那么就有那个小勾,如果没有装就不会有那个小勾,然后把那个小勾勾上,在单击下一步之前请先将你的系统光盘放入光区就可以了。34:如何配置IIS?首先打开IIS,依次展开本地计算机网站默认网站,右键单击默认网站,选择属性.如图:

然后选择目录安全性,单击编辑.如图:45将集成windows身份验证前的勾勾上.5:补充如果你的电脑上装了.NET2003,又装了.NET2005的话,那么你就要做如下设置.如图:将ASP.NET版本选为你要开发的那个版本就可以了.6第二节:C#.NET介绍1:语法介绍最简单的

"Hello

World

"程序

1:

class

HelloWorld

2:

{

3:

public

static

void

Main()

4:

{

5:

System.Console.WriteLine("Hello

World");

6:

}

7:

}

在C#中,代码块(语句组)由大括弧({和})所括住。所以,甚至你以前没有C++的经验,你也可以说出Main()方法就是HelloWorld

类语句的一部分,因为类被括在所定义的大括弧中。

C#应用程序(可执行)的入口点就是

static

Main

方法,它必须包含在一个类中。仅有一个类能使用该标志定义,除非你告诉编译器它应使用哪一个

Main

方法(否侧,会产生一个编译错误)。

和C++相比,Main的第一个字母是大写的M,而不是你曾经使用过的小写字母。在这个方法中,你的程序开始并结束。方法中可以调用其它方法——如这个例子中,用于输出文本——或者创建对象并激活该方法。

正如你所看到的,Main方法返回一个void类型。

public

static

void

Main()

尽管看到这些语句时,C++程序员肯定会觉得似曾相识,但是其他程序员并不如此。首先,public

的访问标志告诉我们这个方法可以被任何程序访问,这是它被调用的必要条件。其次,static

意味着没有先创建类的实例也可以调用方法——你所要做的就是用类名调用方法。

HelloWorld.Main();

但是,我不赞成在Main方法中执行这行代码,递归会导致堆栈溢出。

另一重要的方面是返回类型。对于方法Main,可选择void

(意味着根本就没有返回值),或用int

为整型结果(应用程序返回的错误级别)。因此,两种可能的Main方法为:

public

static

void

Main()

public

static

int

Main()

7大家在看下面这个列子:

using

System;

2:

3:

class

HelloWorld

4:

{

5:

public

static

void

Main()

6:

{

7:

Console.WriteLine(“Hello

World”);

8:

}

9:

}

让我们把注意力集中到唯一真正的代码行——这行代码在屏幕上显示“Hello

Wold”。

System.Console.WriteLine(“Hello

World”);

假如不是由于有了System,大家会马上猜到WriteLine是Console

对象的一个静态方法。那么System代表什么呢?

它是包含Console对象的名字空间(范围),实际上并不是每次都在Console对象前加上名字空间的前缀,你可以象清单3.2所示范的那样,在应用程序中引入名字空间。

所有你要做的就是给System名字空间加一个using指令。在这之后,不再需要规定名字空间,就可以使用它们的方法和属性了。NGWS

框架体系中有很多的名字空间,我只对巨大的名字空间池中的少数几个对象进行探讨。在后面我们将介绍为你的对象创建自己的名字空间。

82:输入和输出

到目前为止,我仅仅演示了把简单的常量字符串输出到屏幕。尽管这本书只介绍了C#编程的概念而不介绍用户接口编程,但我需要让你迅速学会简单的屏幕输入和输出方法——相应于C的scanf

printf,或者C++的cin

和cout。我不能提供VB相应的函数,因为屏幕访问不是该核心语言的一部分。

你只需要能够读用户的输入并提示一些信息给用户。清单3.3

说明如何读一个用户请求的名字输入,并显示一条已定制好的"Hello"

信息。

从控制台读输入信息

1:

using

System;

2:

3:

class

InputOutput

4:

{

5:

public

static

void

Main()

6:

{

7:

Console.Write("Please

enter

your

name:

");

8:

string

strName

=

Console.ReadLine();

9:

Console.WriteLine("Hello

"

+

strName);

10:

}

11:

}

第7行使用Console对象的一个新方法用于提示文本信息给用户,它就是Write方法。它与WriteLine不同的地方在于它输出时不换行。我使用这种方法以便用户可以在信息提示的同一行输入名字。

在用户输入他的名字后(并按回车键),ReadLine

方法读入了一个字符串变量。名字字符串连接到常量字符串“Hello”,并用我们早已熟悉的WriteLine方法显示出来(见图3.2)。93:编译和运行定制的Hello

应用程序

你几乎已学完了NGWS框架必要的输入和输出功能。但是,你还需要为用户显示多个值。为用户写一个格式串。清单3.4展示一个例子。

清单

3.4

使用不同的输出方法

1:

using

System;

2:

3:

class

InputOutput

4:

{

5:

public

static

void

Main()

6:

{

7:

Console.Write(“Please

enter

your

name:

”);

8:

string

strName

=

Console.ReadLine();

9:

Console.WriteLine(“Hello

{0}”,strName);

10:

}

11:

}

第9行包含了使用格式串的Console.WriteLine语句。格式串例子如下:

“Hello

{0}”

{0}代替WriteLine方法的参数表中紧随格式串后的第一个变量。你可以用该技术格式化超过三个变量。

Console.WriteLine(“Hello

{0}

{1},

from

{2}”,

strFirstname,

strLastname,

strCity);

当然,并不仅限于只使用字符串变量。你可以使用任何类型.104:添加注释

当写代码时,你应为代码写注释条文,解释实现的内容、变更史等。尽管你注释中提供的信息(如果有的话)是给你写的,但是你还是必须遵守写C#注释的方法。清单3.5

显示采用的两种不同的方式。

清单3.5

给你的代码添加注释

1:

using

System;

2:

3:

class

HelloWorld

4:

{

5:

public

static

void

Main()

6:

{

7:

//

这是单行注释

8:

/*

这种注释

9:

跨越多行

*/

10:

Console.WriteLine(/*“Hello

World”*/);

11:

}

12:

}

11“//”

符号用于单行注释。你可以用“//”注释当前所在行,或是跟在一个代码语句的后面:

int

nMyVar

=

10;

//

注释

所有在“//”后面的被认为是一条注释;所以,你可以同样用它们来注释一整行或一行源代码的部分。这种注释方式同C++中介绍的相似。

如果你的注释跨越多行,必须使用“/*

*/”的字符组合。这种方式在C中有效。除了单行注释外,这种方式在C++和C#中还同样有效。因C/C++和C#都使用这种多行注释方式,所以它们也使用相同的终结符。请看下列代码行:

/*

Console.WriteLine(“Hello

World”);

*/

我使用“/*

*/”简单地注释一整行。现在我假定这一行是很长代码的一部分,而且我决定要暂时禁用一个程序块:

/*

...

/*

Console.WriteLine(“Hello

World”);

*/

...

*/

这个结构所存在的问题为:

“Hello

World”那一行后面的“*/”终止了始于第一行的“/*”的注释,余下的代码对编译器有效,你将看到一些有趣的出错信息。至少

最后的“*/”被标志为归属错误。

125:C#类型

5.1

值类型

各种值类型总是含有相应该类型的一个值。C#迫使你初始化变量才能使用它们进行计算-变量没有初始化不会出问题,因为当你企图使用它们时,编译器会告诉你。

每当把一个值赋给一个值类型时,该值实际上被拷贝了。相比,对于引用类型,仅是引用被拷贝了,而实际的值仍然保留在相同的内存位置,但现在有两个对象指向了它(引用它)。C#的值类型可以归类如下:

·简单类型(Simple

types

·结构类型(struct

types)

·枚举类型(Enumeration

types)

5.1.1

简单类型

在C#中出现的简单类型共享一些特性。第一,它们都是.NET系统类型的别名。第二,由简单类型组成的常量表达式仅在编译时而不是运行时受检测。最后,简单类型可以按字面被初始化。以下为C#简单类型归类:

·整型

·布尔型

·

字符型

(整型的一种特殊情况)

·浮点型

·小数型

13整型

C#中有9个整型。

sbyte

、byte、

short、

ushort、

int、

uint、

long、

ulong

char(单独一节讨论)。它们具有以下特性:

·sbyte型为有符号8位整数,取值范围在128~127之间。

·bytet型为无符号16位整数,取值范围在0~255之间。

·short型为有符号16位整数,取值范围在-32,768~32,767之间。

·ushort型为无符号16位整数,取值范围在0~65,535之间。

·int型为有符号32位整数,取值范围在-2,147,483,648~

2,147,483,647之间。

·uint型为无符号32位整数,取值范围在

0

~

4,294,967,295之间。

·long型为64位有符号整数,取值范围在9,223,372,036,854,775,808~

9,223,372,036,854,775,807之间。

·ulong型为64位无符号整数,取值范围在0

~

18,446,744,073,709,551,615之间。

VB和C程序员都可能会对int和long数据类型所代表的新范围感到惊讶。和其它的编程语言相比,在C#中,int不再取决于一个机器的字(word)的大小,而long被设成64位。14布尔型

布尔数据类型有true和false两个布尔值。可以赋于true或false值给一个布尔变量,或可以赋于一个表达式,其所求出的值等于两者之一:

bool

bTest

=

(80

>

90);

与C和C++相比,在C#中,true值不再为任何非零值。不要为了增加方便而把其它整型转换成布尔型。

15字符型

字符型为一个单Unicode

字符。一个Unicode字符16位长,它可以用来表示世界上多种语言。可以按以下方法给一个字符变量赋值:

char

chSomeChar

=

'A';

除此之外,可以通过十六进制转义符(前缀\x)或Unicode表示法给变量赋值(前缀\u):

char

chSomeChar

=

'\x0065';

char

chSomeChar

=

'\u0065';

不存在把char转换成其它数据类型的隐式转换。这就意味着,在C#中把一个字符变量当作另外的整数数据类型看待是行不通的——这是C程序员必须改变习惯的另一个方面。但是,可以运用显式转换:

char

chSomeChar

=

(char)65;

int

nSomeInt

=

(int)'A';

在C中仍然存在着转义符(字符含义)。16转义符

字符名

\'

单引号

\"

双引号

\\

反斜杠

\0

空字符

\a

感叹号(Alert

\b

退格

\f

换页

\n

新行

\r

回车

\t

水平

tab

\v

垂直tab

17浮点型

两种数据类型被当作浮点型:float和double。它们的差别在于取值范围和精度:

float:

取值范围在

1.5x10^-45~

3.4x10^38之间,

精度为7位数。

double:

取值范围在

5.0x10^-324

~

1.7x10^308之间,

精度为

15~16

位数。

当用两种浮点型执行运算时,可以产生以下的值:

正零和负零

正无穷和负无穷

非数字值(Not-a-Number,缩写NaN)

非零值的有限数集

另一个运算规则为,当表达式中的一个值是浮点型时,所有其它的类型都要被转换成浮点型才能执行运算。

18小数型(The

decimal

Type)

小数型是一种高精度、128位数据类型,它打算用于金融和货币的计算。它所表示的范围从大约1.0x10^-28

7.9x10^28,具有28至29位有效数字。要注意,精度是以位数

(digits)而不是以小数位(decimal

places)表示。运算准确到28个小数位的最大值。

正如你所看到的,它的取值范围比double的还窄,但它更精确。因此,没有decimal和double之间的隐式转换——往一个方向转换可能会溢出,往另外一个方向可能会丢失精度。你不得不运用显式转换。

当定义一个变量并赋值给它时,使用

m

后缀以表明它是一个小数型:

decimal

decMyValue

=

1.0m;

如果省略了m,在变量被赋值之前,它将被编译器认作double型。19结构类型

一个结构类型可以声明构造函数、常数、字段、方法、属性、索引、操作符和嵌套类型。尽管列出来的功能看起来象一个成熟的类,但在C#中,结构和类的区别在于结构是一个值类型,而类是一个引用类型。与C++相比,这里可以用结构关键字定义一个类。

使用结构的主要思想是用于创建小型的对象,如Point和等等。你可以节省内存,因为没有如类对象所需的那样有额外的引用产生。例如,当声明含有成千上万个对象的数组时,这会引起极大的差异。

清单4.1

包含一个命名为IP的简单结构,它表示一个使用byte类型的4个字段的IP地址。我不包括方法等,因为这些工作正如使用类一样,将在下一章有详细的描述。

20定义一个简单的结构

1:

using

System;

2:

3:

struct

IP

4:

{

5:

public

byte

b1,b2,b3,b4;

6:

}

7:

8:

class

Test

9:

{

10:

public

static

void

Main()

11:

{

12:

IP

myIP;

13:

myIP.b1

=

192;

14:

myIP.b2

=

168;

15:

myIP.b3

=

1;

16:

myIP.b4

=

101;

17:

Console.Write("{0}.{1}.",myIP.b1,myIP.b2);

18:

Console.Write("{0}.{1}",myIP.b3,myIP.b4);

19:

}

20:

}

21枚举类型

当你想声明一个由一指定常量集合组成的独特类型时,枚举类型正是你要寻觅的。最简单的形式,它看起来可能象这样:

enum

MonthNames

{

January,

February,

March,

April

};

因我惯用缺省设置,故枚举元素是int型,且第一个元素为0值。每一个连续的元素按1递增。如果你想给第一个元素直接赋值,可以如下把它设成1:

enum

MonthNames

{

January=1,

February,

March,

April

};

如果你想赋任意值给每个元素——甚至相同的值——这也没有问题:

enum

MonthNames

{

January=31,

February=28,

March=31,

April=30

};

最后的选择是不同于int的数据类型。可以在一条语句中按如此赋值:

enum

MonthNames

:

byte

{

January=31,

February=28,

March=31,

April=30

};

你可以使用的类型仅限于long、int、short和byte。

22类类型

一个类类型可以包含数据成员、函数成员和嵌套类型。数据成员是常量、字段和事件。函数成员包括方法、属性、索引、操作符、构造函数和析构函数。类和结构的功能是非常相似的,但正如前面所述,结构是值类型而类是引用类型。

和C++相比,仅允许单继承。(你不能拥有派生一个新对象的多重基类。)

但是,C#中的一个类可以派生自多重接口,该接口在下一节将得到描述。

第五章

“类”专门讨论使用类编程。这一节仅打算给出C#类在哪里适合类型图的一个全貌。

23接口

一个接口声明一个只有抽象成员的引用类型。跟C++中相似的概念为:一个结构的成员,且方法等于0。如果你不知道那些概念的任何东西,这里就是在C#中一个接口实际所做的。仅仅只存在着方法标志,但根本就没有执行代码。这就暗示了不能实例化一个接口,只能实例化一个派生自该接口的对象。

可以在一个接口中定义方法、属性和索引。所以,对比一个类,接口有什么特殊性呢?当定义一个类时,可以派生自多重接口,而你只能可以从仅有的一个类派生。

你可能会问:"OK,但我必须实现所有的接口成员,那么我能从这个途径得到什么呢?"

我想举一个来自.NET的例子:很多类实现了IDictionary

接口。你可以使用简单的类型转换访问接口:24IDictionary

myDict

=

(IDictionary)someobjectthatsupportsit;

现在你的代码可以访问字典了。可等等,我说很多类可以实现这个接口——所以,你可以在多个地方重用代码来访问IDictionary

接口!一旦学会,任何地方都可使用。

当你决定在类设计中使用接口时,学习更多关于面向对象的设计是个好主意。这本书不能教你这些概念,但你可以学习如何创建接口。以下的代码段定义接口IFace,它只有一个方法:

interface

IFace

{

void

ShowMyFace();

}

正如我所提到的,不能从这个定义实例化一个对象,但可以从它派生一个类。因此,该类必须实现ShowMyFace抽象方法:

class

CFace:IFace

{

public

void

ShowMyFace()

{

Console.WriteLine("implementation");

}

}

接口成员和类成员的区别在于,接口成员不能被实现。256:异常处理

通用语言运行时(CLR)具有的一个很大的优势为,异常处理是跨语言被标准化的。一个在C#中所引发的异常可以在Visual

Basic客户中得到处理。不再有

HRESULTs

或者

ISupportErrorInfo

接口。

尽管跨语言异常处理的覆盖面很广,但这一章完全集中讨论C#异常处理。你稍为改变编译器的溢出处理行为,接着有趣的事情就开始了:你处理了该异常。要增加更多的手段,随后引发你所创建的异常。

7.1

校验(checked)和非校验(unchecked)语句

当你执行运算时,有可能会发生计算结果超出结果变量数据类型的有效范围。这种情况被称为溢出,依据不同的编程语言,你将被以某种方式通知——或者根本就没有被通知。(C++程序员听起来熟悉吗?)

那么,C#如何处理溢出的呢?

要找出其默认行为,请看我在这本书前面提到的阶乘的例子。26计算一个数的阶乘

1:

using

System;

2:

3:

class

Factorial

4:

{

5:

public

static

void

Main(string[]

args)

6:

{

7:

long

nFactorial

=

1;

8:

long

nComputeTo

=

Int64.Parse(args[0]);

9:

10:

long

nCurDig

=

1;

11:

for

(nCurDig=1;nCurDig

<=

nComputeTo;

nCurDig++)

12:

nFactorial

*=

nCurDig;

13:

14:

Console.WriteLine("{0}!

is

{1}",nComputeTo,

nFactorial);

15:

}

16:

}

当你象这样使用命令行执行程序时

factorial

2000

结果为0,什么也没有发生。因此,设想C#默默地处理溢出情况而不明确地警告你是安全的。

通过给整个应用程序(经编译器开关)或于语句级允许溢出校验,你就可以改变这种行为。27异常处理语句

既然你知道了如何产生一个异常(你会发现更多的方法,相信我),仍然存在如何处理它的问题。如果你是一个

C++

WIN32

程序员,肯定熟悉SEH(结构异常处理)。你将从中找到安慰,C#中的命令几乎是相同的,而且它们也以相似的方式运作。

The

following

three

sections

introduce

C#'s

exception-handling

statements:

以下三节介绍了C#的异常处理语句:

。用

try-catch

捕获异常

。用try-finally

清除异常

。用try-catch-finally

处理所有的异常

28使用

try

catch捕获异常

这样使用的语句是try

catch。try包含可能会产生异常的语句,而catch处理一个异常,如果有异常存在的话。下面是

用try

catch为OverflowException

实现异常处理。

捕获由Factorial

Calculation引发的OverflowException

异常

1:

using

System;

2:

3:

class

Factorial

4:

{

5:

public

static

void

Main(string[]

args)

6:

{

7:

long

nFactorial

=

1,

nCurDig=1;

8:

long

nComputeTo

=

Int64.Parse(args[0]);

9:

10:

try

11:

{

12:

checked

13:

{

14:

for

(;nCurDig

<=

nComputeTo;

nCurDig++)

15:

nFactorial

*=

nCurDig;

16:

}

17:

}

18:

catch

(OverflowException

oe)

19:

{

20:

Console.WriteLine("Computing

{0}

caused

an

overflow

exception",

nComputeTo);

21:

return;

22:

}

23:

24:

Console.WriteLine("{0}!

is

{1}",nComputeTo,

nFactorial);

25:

}

26:

}

29为了说明清楚,我扩展了某些代码段,而且我也保证异常是由checked

语句产生的,甚至当你忘记了编译器设置时。

正如你所见,异常处理并不麻烦。你所有要做的是:在try语句中包含容易产生异常的代码,接着捕获异常,该异常在这个例子中是OverflowException类型。无论一个异常什么时候被引发,在catch段里的代码会注意进行适当的处理。

如果你不事先知道哪一种异常会被预期,而仍然想处于安全状态,简单地忽略异常的类型。

try

{

...

}

catch

{

...

}

但是,通过这个途径,你不能获得对异常对象的访问,而该对象含有重要的出错信息。一般化异常处理代码象这样:

try

{

...

}

catch(System.Exception

e)

{

...

}

注意,你不能用ref或out

修饰符传递

e

对象给一个方法,也不能赋给它一个不同的值。

30使用

try

finally

清除异常

如果你更关心清除而不是错误处理,

try

finally

会获得你的喜欢。它不仅抑制了出错消息,而且所有包含在

finally

块中的代码在异常被引发后仍然会被执行。

尽管程序不正常终止,但你还可以为用户获取一条消息.

在finally

语句中处理异常

1:

using

System;

2:

3:

class

Factorial

4:

{

5:

public

static

void

Main(string[]

args)

6:

{

7:

long

nFactorial

=

1,

nCurDig=1;

8:

long

nComputeTo

=

Int64.Parse(args[0]);

9:

bool

bAllFine

=

false;

10:

11:

try

12:

{

13:

checked

14:

{

15:

for

(;nCurDig

<=

nComputeTo;

nCurDig++)

16:

nFactorial

*=

nCurDig;

17:

}

18:

bAllFine

=

true;

19:

}

20:

finally

21:

{

22:

if

(!bAllFine)

23:

Console.WriteLine("Computing

{0}

caused

an

overflow

exception",

nComputeTo);

24:

else

25:

Console.WriteLine("{0}!

is

{1}",nComputeTo,

nFactorial);

26:

}

27:

}

28:

}

31通过检测该代码,你可能会猜到,即使没有引发异常处理,finally也会被执行。这是真的——在finally中的代码总是会被执行的,不管是否具有异常条件。为了举例说明如何在两种情况下提供一些有意义的信息给用户,

我引进了新变量bAllFine。bAllFine告诉finally

语段,它是否是因为一个异常或者仅是因为计算的顺利完成而被调用。

作为一个习惯了SEH程序员,你可能会想,是否有一个与__leave

语句等价的语句,该语句在C++中很管用。如果你还不了解,在C++中的__leave

语句是用来提前终止

try

语段中的执行代码,并立即跳转到finally

语段

坏消息,

C#

中没有__leave

语句。但是,在清单

7.5

中的代码演示了一个你可以实现的方案。

32清单

7.5

try语句

跳转到finally

语句

1:

using

System;

2:

3:

class

JumpTest

4:

{

5:

public

static

void

Main()

6:

{

7:

try

8:

{

9:

Console.WriteLine("try");

10:

goto

__leave;

11:

}

12:

finally

13:

{

14:

Console.WriteLine("finally");

15:

}

16:

17:

__leave:

18:

Console.WriteLine("__leave");

19:

}

20:

}

33这个应用程序运行时,输出结果为

try

finally

__leave

一个

goto

语句不能退出

一个finally

语段。甚至把

goto

语句放在

try

语句

段中,还是会立即返回控制到

finally

语段。因此,goto

只是离开了

try

语段并跳转到finally

语段。直到

finally

中的代码完成运行后,才能到达__leave

标签。按这种方式,你可以模仿在SEH中使用的的__leave

语句。

顺便地,你可能怀疑goto

语句被忽略了,因为它是try

语句中的最后一条语句,并且控制自动地转移到了

finally

。为了证明不是这样,试把goto

语句放到Console.WriteLine

方法调用之前。尽管由于不可到达代码你得到了编译器的警告,但是你将看到goto语句实际上被执行了,且没有为

try

字符串产生的输出。

34使用try-catch-finally处理所有异常

应用程序最有可能的途径是合并前面两种错误处理技术——捕获错误、清除并继续执行应用程序。所有你要做的是在出错处理代码中使用

try

、catch

finally语句。清单

7.6

显示了处理零除错误的途径。

清单

7.6

实现多个catch

语句

1:

using

System;

2:

3:

class

CatchIT

4:

{

5:

public

static

void

Main()

6:

{

7:

try

8:

{

9:

int

nTheZero

=

0;

10:

int

nResult

=

10

/

nTheZero;

11:

}

12:

catch(DivideByZeroException

divEx)

13:

{

14:

Console.WriteLine("divide

by

zero

occurred!");

15:

}

16:

catch(Exception

Ex)

17:

{

18:

Console.WriteLine("some

other

exception");

19:

}

20:

finally

21:

{

22:

}

23:

}

24:

}

35这个例子的技巧为,它包含了多个catch

语句。第一个捕获了更可能出现的DivideByZeroException异常,而第二个catch语句通过捕获普通异常处理了所有剩下来的异常。

你肯定总是首先捕获特定的异常,接着是普通的异常。如果你不按这个顺序捕获异常,会发生什么事呢?清单7.7中的代码有说明。

36清单7.7

顺序不适当的

catch

语句

1:

try

2:

{

3:

int

nTheZero

=

0;

4:

int

nResult

=

10

/

nTheZero;

5:

}

6:

catch(Exception

Ex)

7:

{

8:

Console.WriteLine("exception

"

+

Ex.ToString());

9:

}

10:

catch(DivideByZeroException

divEx)

11:

{

12:

Console.WriteLine("never

going

to

see

that");

13:

}

37编译器将捕获到一个小错误,并类似这样报告该错误:

wrongcatch.cs(10,9):

error

CS0160:

A

previous

catch

clause

already

catches

all

exceptions

of

this

or

a

super

type

(‘System.Exception’)

最后,我必须告发CLR异常与SEH相比时的一个缺点(或差别):没有

EXCEPTION_CONTINUE_EXECUTION标识符的等价物,它在SEH异常过滤器中很有用。基本上,EXCEPTION_CONTINUE_EXECUTION

允许你重新执行负责异常的代码片段。在重新执行之前,你有机会更改变量等。我个人特别喜欢的技术为,使用访问违例异常,按需要实施内存分配。

38引发异常

当你必须捕获异常时,其他人首先必须首先能够引发异常。而且,不仅其他人能够引发,你也可以负责引发。其相当简单:

throw

new

ArgumentException("Argument

can't

be

5");

你所需要的是throw

语句和一个适当的异常类。我已经从表7.1提供的清单中选出一个异常给这个例子。

39异常类型

描述

Exception

所有异常对象的基类

SystemException

运行时产生的所有错误的基类

IndexOutOfRangeException

当一个数组的下标超出范围时运行时引发

NullReferenceException

当一个空对象被引用时运行时引发

InvalidOperationException

当对方法的调用对对象的当前状态无效时,由某些方法引发

ArgumentException

所有参数异常的基类

ArgumentNullException

在参数为空(不允许)的情况下,由方法引发

ArgumentOutOfRangeException

当参数不在一个给定范围之内时,由方法引发

InteropException

目标在或发生在CLR外面环境中的异常的基类

ComException

包含COM

类的HRESULT信息的异常

SEHException

封装win32

结构异常处理信息的异常

然而,在catch语句的内部,你已经有了随意处置的异常,就不必创建一个新异常。可能在表7.1

中的异常没有一个符合你特殊的要求——为什么不创建一个新的异常?在即将要学到小节中,都涉及到这两个话题。

40异常处理的“要”和“不要”

作为最后的忠告之语,这里是对异常引发和处理所要做和不要做的清单:

。当引发异常时,要提供有意义的文本。

。要引发异常仅当条件是真正异常;也就是当一个正常的返回值不满足时。

。如果你的方法或属性被传递一个坏参数,要引发一个ArgumentException异常。

。当调用操作不适合对象的当前状态时,要引发一个

InvalidOperationException异常。

。要引发最适合的异常。

。要使用链接异常,它们允许你跟踪异常树。

。不要为正常或预期的错误使用异常。

。不要为流程的正常控制使用异常。

。不要在方法中引发

NullReferenceException或IndexOutOfRangeException异常。

7.5

小结

这一章由介绍溢出校验开始。你可以使用编译器开关(默认是关),使整个应用程序允许或禁止溢出校验。如果需要微调控制,你可以使用校验和非校验语句,它允许你使用或不使用溢出校验来执行一段代码,尽管没有给应用程序设置开关。

当发生溢出时,一个异常就被引发了。如何处理异常取决于你。我提出了各种途径,包括你最有可能贯穿整个应用程序使用的:try、catch

和finally

语句。在伴随的多个例子中,你学到了它与WIN32结构异常处理(SEH)的差别。

异常处理是给类的用户;

然而,如果你负责创建新的类,就可以引发异常。有多种选择:引发早已捕获的异常,引发存在的框架异常,或者按规定的实际目标创建新的异常类。

最后,你需要阅读引发和处理异常的各种“要”和“不要”。

41作业用实例说明:1:未实例化对象可以引用方法吗?2:try发生异常或returnfinally会执行吗?427:类的写法

前一章讨论了数据类型和它们的用法。现在我们转移到C#中至关重要的结构——类。没有了类,就连简单的C#程序都不能编译。这一章你将学到下列有关类的话题。

43首先我们来看下面的一个例子:

publicSqlConnectiongetConn(){StringSqlConn=“server=.;database=SPCompany;uid=sa;pwd=sa;";SqlConnectionmyConn=newSqlConnection(SqlConn);returnmyConn;}44publicintexecuteSql(SqlConnectionmyConn,StringstrSql) { //打开连接 myConn.Open(); SqlCommandmyComm=newSqlCommand(); SqlTransactionmyTran; //创建一个事务 myTran=myConn.BeginTransaction(); //从此开始,基于该连接的数据操作都被认为是事务的一部分 //下面绑定连接和事务对象 myComm.Connection=myConn; myComm.Transaction=myTran;} 45try { //执行SQL语句 myComm.CommandText=strSql; intcount=myComm.ExecuteNonQuery(); //提交事务 myTran.Commit(); //返回影响的记录数(更新数、删除数) returncount; } catch(Exceptionerr) { myTran.Rollback(); Console.Write(err+"|||SQL:"+strSql); // Console.Write("事务操作出错,已回滚。系统信息:"+err.Message); return0; } finally { myConn.Close(); }

}46上面是一个数据库连接的类和一个打开数据库的类,下次调用的时候就会很简单了;下面我们来看下调用的代码:this.connectionManager=newConnectionManager(); //实例化connectionManager对象 this.myConn=this.connectionManager.getConn();//调用这个方法

具体的操作方法我们将会在上机的时候给你们演示。47以下是一些常用类的写法:1:打开连接,执行操作publicSqlDataReadergetDataReader(SqlConnectionmyConn,StringstrSql) { //打开连接 myConn.Open(); SqlCommandmyComm=newSqlCommand(); SqlDataReadermyReader; myComm.Connection=myConn;48 try { //执行SQL语句 myComm.CommandText=strSql; myReader=myComm.ExecuteReader(); //返回检索的结果 returnmyReader; } catch(Exceptionerr) { Console.Write(err+"|||SQL:"+strSql); // Console.Write("事务操作出错,已回滚。系统信息:"+err.Message); returnnull; } finally { //myConn.Close(); } }492:创建数据集publicDataSetgetDataSet(SqlConnectionmyConn,StringstrSql) { //打开连接 myConn.Open(); SqlDataAdaptersqldar; DataSetdataSet;50 try { sqldar=newSqlDataAdapter(strSql,myConn); sqldar.SelectCommand.CommandType=CommandType.Text; dataSet=newDataSet(); sqldar.Fill(dataSet,"MyTable"); //返回检索的结果 returndataSet; } catch(Exceptionerr) { Console.Write(err+"|||SQL:"+strSql); // Console.Write("事务操作出错,已回滚。系统信息:"+err.Message); returnnull; } finally {myConn.Close(); } }513:绑定城市下拉框的类publicvoidsetChengShiList(DropDownListdrpDownList){try{sql="selectChengShiID,ChengShiMingChengfromChengShi";DataSetdataSet;dataSet=connectionManager.getDataSet(myConn,sql);drpDownList.Items.Clear();drpDownList.Items.Add(newListItem("请选择...",""));for(inti=0;i<dataSet.Tables["MyTable"].Rows.Count;i++){drpDownList.Items.Add(newListItem(dataSet.Tables["MyTable"].Rows[i][1].ToString(),dataSet.Tables["MyTable"].Rows[i][0].ToString()));}}52catch(Exceptionerr){logger.Info(err+"|SQL:"+sql);}finally{if(myConn!=null){myConn.Close();myConn=null;}}}53Web.Config文件详解(一).Web.Config是以XML文件规范存储,配置文件分为以下格式1.配置节处理程序声明特点:位于配置文件的顶部,包含在<configSections>标志中。2.特定应用程序配置特点:位于<appSetting>中。可以定义应用程序的全局常量设置等信息.3.配置节设置特点:位于<system.Web>节中,控制A运行时的行为.4.配置节组特点:用<sectionGroup>标记,可以自定义分组,可以放到<configSections>内部或其它<sectionGroup>标记的内部.54(二).配置节的每一节1.<configuration>节

根元素,其它节都是在它的内部.2.<appSetting>节

此节用于定义应用程序设置项。对一些不确定设置,还可以让用户根据自己实际情况自己设置用法<appSettings>

<addkey="Conntction"value="server=6;userid=sa;password=;database=Info;"/>

<appSettings>定义了一个连接字符串常量,并且在实际应用时可以修改连接字符串,不用修改程式代码.553.<compilation>节格式:

<compilationdefaultLanguage="c#"

debug="true"/>I.defaultlanguage:定义后台代码语言,可以选择C#和VB.net两种语言.IIdebug:为true时,启动aspx调试;为false不启动aspx调试,因而可以提高应用程序运行时的性能。一般程序员在开发时设置为true,交给客户时设置为false.564.<customErrors>节格式:

<customErrorsmode="RemoteOnly"

defaultRedirect="error.aspx"

<errorstatusCode="440"redirect="err440page.aspx"/>

<errorstatusCode="500"redirect="err500Page.aspx"/>/>I.mode:具有On,Off,RemoteOnly3种状态。On表示始终显示自定义的信息;Off表示始终显示详细的错误信息;RemoteOnly表示只对不在本地Web服务器上运行的用户显示自定义信息.

57II.defaultRedirect:用于出现错误时重定向的URL地址.是可选的III.statusCode:指明错误状态码,表明一种特定的出错状态.IV.redirect:错误重定向的URL.5.<globalization>节格式:

<globalization

requestEncoding="utf-8"

responseEncoding="utf-8"

"utf-8"

/>58I.requestEncoding:它用来检查每一个发来请求的编码.II.responseEncoding:用于检查发回的响应内容编码.III.:用于检查aspx,asax等文件解析的默认编码.6.<sessionState>节格式:

<sessionState

mode="InProc"

stateConnectionString="tcpip=:42424"

sqlConnectionString="datasource=;Trusted_Connection=yes"

cookieless="false"

timeout="20"

/>59I.mode:分为off,Inproc,StateServer,SqlServer几种状态这里有详细介绍此属性:II.stateConnectionString:指定A应用程序存储远程会话状态的服务器名,默认为本机III.sqlConnectionString:当用会话状态数据库时,在这里设置连接字符串IV.Cookieless:设置为true时,表示不使用cookie会话状态来标识客户;否则,相反.V.TimeOut:用来定义会话状态存储的时间,超过期限,将自动终止会话.607.<authentication>节格式:

<authenticationmode="Forms">

<formsname=".ASPXUSERDEMO"loginUrl="Login.aspx"protection="All"timeout="30"/>

</authentication>

<authorization>

<denyusers="?"/>

</authorization>I.Windows:使用IIS验证方式61II.Forms:使用基于窗体的验证方式III.Passport:采用Passportcookie验证模式IV.None:不采用任何验证方式里面内嵌Forms节点的属性涵义:I.Name:指定完成身份验证的Httpcookie的名称.II.LoginUrl:如果未通过验证或超时后重定向的页面URL,一般为登录页面,让用户重新登录III.Protection:指定cookie数据的保护方式.62可设置为:AllNoneEncryptionValidation四种保护方式a.All表示加密数据,并进行有效性验证两种方式b.None表示不保护Cookie.c.Encryption表示对Cookie内容进行加密d.validation表示对Cookie内容进行有效性验证IV.TimeOut:指定Cookie的失效时间.超时后要重新登录.63练习在界面输入用户名密码并从web.config读取正确用户名密码验证。64Log的配置和使用一Log4net简介二Log4net核心组成三如何在项目中使用log4net65Log4net是基于.net开发的一款非常著名的记录日志开源组件。他最早是2001年7月由NeoWorksLimited启动的项目,基本的框架源于另外的一个非常著名的姐妹组件-log4j。Log4net记录日志的功能非常强大。它可以将日志分不同的等级,比不同的样式,将日志输出到不同的媒介。Log4net可以从网站下载最新版本。一Log4net简介66二Log4net核心组成Log4net主要由五个部分组成,分别为Logger,Appenders,Filters,Layouts和ObjectRenders。67一)Logger(日志)1.记录日志的分类:Log4net能够以多种方式输出日志。支持的日志输出常用的主要媒介有数据库(包括MSSQLServer,Access,Oracle9i,Oracle8i,DB2,SQLite,控制台,文件,事件日志(可以用事件查看器查看)和邮件等多种方式。

2.日志的级别Log4net支持多种级别的日志。优先级从高到低依次排列如下:FATAL>ERROR>WARN>INFO>DEBUG此外还有ALL(允许所有的日志请求)和OFF(拒绝所有的日志请求)这两种特殊的级别。68二)Appenders

Appenders决定日志输出的方式。Appenders必须实现log4net.Appenders.IAppender接口。

Log4net目前支持的输出方式包括:

1AdoNetAppender

将日志记录到数据库中。可以采用SQL和存储过程两种方式。2AnsiColorTerminalAppender

在ANSI窗口终端写下高亮度的日志事件。3AspNetTraceAppender

能用中Trace的方式查看记录的日志。4BufferingForwardingAppender

在输出到子Appenders之前先缓存日志事件。

5ConsoleAppender

将日志输出到控制台。6EventLogAppender

将日志写到WindowsEventLog.697

将日志写到文件中。8LocalSyslogAppender

将日志写到localsyslogservice(仅用于UNIX环境下).

9MemoryAppender

将日志存到内存缓冲区。10NetSendAppender

将日志输出到WindowsMessengerservice.这些日志信息将在用户终端的对话框中显示。11RemoteSyslogAppender

通过UDP网络协议将日志写到Remotesyslogservice。12RemotingAppender

通过.NETRemoting将日志写到远程接收端。13Rolling

将日志以回滚文件的形式写到文件中。14SmtpAppender

将日志写到邮件中。15TraceAppender

将日志写到.NETtrace系统。16UdpAppender

将日志connectionlessUDPdatagrams的形式送到远程宿主或以UdpClient的形式广播。70三)Filters

Appender对象将日志以缺省的方式传到输出流,然后Filter可以按照不同的标准控制日志的输出。Filter可以再配置文件中配置。最简单的形式是在appender中写明一个Threshold.这样只有级别大于或等于此Threshold的日志才被记录。Filters必须实现log4net.Filters.IFilter接口71四)Layouts

Layouts控制日志显示的格式样式。日志的显示格式如下:"%timestamp[%thread]%-5level%logger-%message%newline"Timestamp:表示程序已经开始执行的时间。单位[毫秒]。Thread:执行当前代码的线程。Level:日志的级别。Logger:日志相关请求的名称。Message:日志消息。

Layouts还可以控制日志的输出样式,比如以普通形式或以xml等形式输出。72五)ObjectRenderers

这是很重要的一项,log4net将按照用户定义的标准输出日志消息。ObjectRenders必须实现log4net.ObjectRenderer.IObjectRenerer接口。73三如何在项目中使用log4net下面有个基于控制台的demo,举例描述了log4net怎么用于输出日志。

本例中,日志将会记录到文件中。一)引用long4net:1:确认本地机上有一个log4net.dll文件,如没有可以在网上下载一个。2:将这个log4net.dll文件引用这个项目中,操作过程如下:74(1)在已经打开的项目中鼠标右击资源管理器中的项目名称,如图75(2)单击添加引用(R)弹出添加引用窗口,在预览中找到log4net.dll文件,如图76(3)点击确定则log4net.dll文件引用完毕;二)主要代码:

1.配置文件Web.Config7778在Web.Config文件加上一下代码<configSections> <sectionname="log4net"type="log4net.Config.Log4NetConfigurationSectionHandler,log4net-net-1.0"/> </configSections>注意:<configSections>必须是<configuration>下的第一个<configSections>另外还须在AssemblyInfo.cs文件里加上下面的代码:[assembly:log4net.Config.XmlConfigurator()]79这样日志就会以文件形式输出,如果想以控制台,事件日至和Access数据库输出只须将<appendername=“”type=“log4net.Appender.”>中的.分别改为.PatternLayout,.EventLogAppender及.AdoNetAppender。<appender-refref=“Rolling”/>改为<appender-ref

ref="ConsoleAppender"

/>

<appender-ref

ref="EventLogAppender"

/>

<appender-ref

ref=“AdoNetAppender_Access”

/>

则可。源代码可以从下载。80练习自己动手配置日志文件,运行时输出日志并查看日志文件里的内容81数据传递Session方式Session可以用来跨页面数据传递,即把某一页面的数据传递到另外一页面。代码说明:Session["name"]=TextBox1.Text;”name”是传递的参数,TextBox1.Text所要传递的值。

Server.Transfer("Default2.aspx");Default2.aspx数据被传递到的页面。Label1.Text=Session["name"].ToString();接收传递值Session.Remove("name");删除Session值82练习在一个页面的TextBox中输入字符串,点击确定按钮,将该字符串传递到另一个页面。83第三节:基本控件的使用及技巧1:Lable控件的使用方法我们先看下面的代码,因为Lable控件比较简单,我们在这里只例举这一个例子,大家以后就知道怎么做了。84<%@PageLanguage="C#"%>

<%@ImportNamespace="System.Data"%>

<ScriptLanguage="C#"Runat="Server">

publicvoidPage_Load(Objectsrc,EventArgse)

{

if(!Page.IsPostBack)

{

label3.Text="这是黑体字,并且带下划线";

}

}

</script>

<html>

<head>

<title>测试Label控件</title>

</head>

<body>

<bold>测试Label控件:<br></bold>

<asp:Labelid="label1"font-size="9pt"font-bold="true"forecolor="red"runat="server">这是红色粗体的文字</asp:Label><br>

<asp:Labelid="label2"font-size="10pt"font-italic="true"forecolor="blue"runat="server"text="这是蓝色斜体的文字"/><br>

<asp:Labelid="label3"font-size="11pt"font-underline="true"runat="server"/>

</body>

</html>852:DropDownList的使用方法

DropDownList控件用来建立一个下拉列表。DropDownList控件中的每个可选项由一个ListItem元素来定义!例如:在.aspx文件里声明一个DropDownList控件。在设计里有如下代码:<html>

<body>

<formrunat="server">

<asp:DropDownListid="drop1"runat="server">

<asp:ListItem>Item1</asp:ListItem>

<asp:ListItem>Item2</asp:ListItem>

<asp:ListItem>Item3</asp:ListItem>

</asp:DropDownList>

</form>

</body>

</html>这样DropDownList的下拉框里就有3个可选项,它们分别为:1,2,386提示:此控件支持数据绑定,即可以直接从数据库里读取可选项。protectedvoidPage_Load(objectsender,EventArgse)

{

SqlConnectionmyconnection=newSqlConnection("server=(local);database=Northwind;uid=sa;pwd=");

stringsql="selectcategoryNamefromcategories";

SqlDataAdaptersda=newSqlDataAdapter(sql,myconnection);

DataSetds=newDataSet();

sda.Fill(ds,"a");

DropDownList1.DataSource=ds.Tables["a"];

DropDownList1.DataTextField="categoryName";

DropDownList1.DataBind();

}DropDownList还包括一些长用的属性,如下:87属性说明AutoPostBack指定在某一项的选择状态发生改变后表单是否被立即投递的一个布尔值。默认值是false

BorderColor指定下拉列表周围边框的颜色

BorderStyle

指定下拉列表周围边框的样式

BorderWidth

指定下拉列表周围边框的宽度

DataSource使用的数据源DataTextField数据源中的一个字段,将被显示于下拉列表中

DataValueField数据源中的一个字段,指定下拉列表中每个可选项的值

id此控件的唯一idOnSelectedIndexChanged当被选项的索引发生改变时将执行的函数的名称runat规定此控件是服务器控件。必须被设置为"server"

883:Gridview的使用在ASP.NET2.0中,加入了许多新的功能和控件,相比1.0/1.1,在各方面都有了很大的提高。其中,在数据控件方面,增加了不少控件,其中的gridview控件功能十分强大。在本文中,将一步步以实际例子介绍asp.ne2.0中gridview控件的简单使用。891.0/1.1,其中的datagrid控件功能是十分强大而且实用的,但随之而来的问题是,感觉在操作上依然不大方便,比如要用写数据的连接,绑定datagr

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论