visual c#.net 程序设计

64
22/6/8 1 Visual C#.NET 程程程程 第8第 第第第第 (第)

Upload: kevina

Post on 24-Jan-2016

109 views

Category:

Documents


0 download

DESCRIPTION

Visual C#.NET 程序设计. 第 8 章 维护数据 ( 二 ). 学习和实践的目标. 需求分析要求:增加、删除、修改与学生成绩相关的基础数据,即学生、学年、课程、教师、成绩比例和操作员。 本章将充分利用对象的继承性和多态性完成所有基础数据的增加、修改和删除。. 实现目标的知识点. 数组 跳转和循环控制 数据类型转换. 8.1 实现目标的步骤. 利用对象的继承性和多态性维护数据的步骤如图 8-1 所示。. 8.2 数组与循环控制处理. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Visual C#.NET 程序设计

23/4/21 1

Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

Page 2: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 2

学习和实践的目标

需求分析要求:增加、删除、修改与学生成绩相关的基础数据,即学生、学年、课程、教师、成绩比例和操作员。

本章将充分利用对象的继承性和多态性完成所有基础数据的增加、修改和删除。

Page 3: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 3

实现目标的知识点

数组 跳转和循环控制 数据类型转换

Page 4: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 4

8.1 实现目标的步骤

利用对象的继承性和多态性维护数据的步骤如图 8-1 所示。

将 f rm增改学生 中的ShowDi al og和Modi fy方法要完成的工作上移至 f rm增改 中,使其惠及派生类

frm增改学生 frm增改

Page 5: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 5

8.2 数组与循环控制处理 数据及其处理总是贯穿在应用程序的整个

开发过程中。相关的数据可以聚合成集。通过数据集的集中处理,可以极大地提高数据处理的灵活性和效率。

8.2.1 数组 以 System.Array 为基类型的数组是一种包含若

干元素的数据结构,是特殊的数据集合。 每个数组中包含的若干个元素都具有相同的数据

类型 , 可通过一个统一的数组变量名和下标(索引)来唯一地确定数组中的元素以进行访问。

C# 中的数组有一维数组、多维数组和交错数组。

Page 6: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 6

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 一维数组的声明格式如下 :

数组类型 [] 数组变量 ; 数组类型可以为 .NET 平台下支持的任意

数据类型,如: Int16 、 Int32和Int64 等,它们都处于 System 命名空间中。假设事先已引入 System 命名空间。

如: Int32[] a;

Page 7: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 7

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 数组类型属于引用类型,因此数组变量的

声明只是为数组实例的引用留出空间,实际的数组实例在运行时使用 new 运算符动态创建。如:

a=new Int32[10]; 以上语句才会使数组 a 成为实际上的、

物理上存在的整型数组,数组 a 将会包含 10个 Int32 型的元素。

Page 8: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 8

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 new 运算符从真正意义上创建了数组,同

时也指定了新数组实例的长度 (length) ,它在该实例的生存期内是固定不变的。

数组元素的索引范围从 0 到 Length - 1 。 new 运算符自动将数组的元素初始化为它

们的默认值,例如将所有数值类型初始化为零,将所有引用类型初始化为 null 。

Page 9: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 9

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 下面的控制台应用程序创建并初始化了一个

Int32 类型的一维数组,同时还在控制台上输出该数组中的内容:

using System; class Test { static void Main() { Int32[] a = new Int32[10]; for (Int32 i = 0; i < a.Length; i++)

a[i] = i * i;

Page 10: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 10

8.2 数组与循环控制处理8.2.1 数组1 .一维数组

for (Int32 i = 0; i < a.Length; i++) { Console.Write ("a["+i+"] = "+a[i]+”

”); } } }

所生成的输出如下: a[0]=0 a[1]=1 a[2]=4 a[3]=9 a[4]=16

a[5]=25 a[6]=36 a[7]=49 a[8]=64 a[9]=81

Page 11: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 11

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 new 运算符还允许使用数组初始值设定项,

以指定数组元素的初始值。数组初始值设定项是在一个位于定界符 {} 之间的表达式列表。下面的示例分配并初始化具有三个元素的 Int32[] :

Int32[] a = new Int32[] {1, 2, 3};

Page 12: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 12

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 注意数组的长度是从 {} 之间的表达式个数

推断出来的。对于局部变量和字段声明,可以进一步简写,不必再次声明数组类型。例如:

Int32[] a = {1, 2, 3}; 前面的两个示例都等效于下面的示例: Int32[] a = new Int32[3]; a[0] = 1; a[1] = 2; a[2] = 3;

Page 13: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 13

8.2 数组与循环控制处理8.2.1 数组1 .一维数组 当一个数组创建表达式既包含显式维度长度,又包含数组初始值设定项时,长度必须是常量表达式,同时各嵌套级别的元素数目必须与相应的维度长度相匹配。参见以下示例:

Int32 i = 3; Int32[] x = new Int32[3] {0, 1, 2}; // 正确 Int32[] y = new Int32[i] {0, 1, 2}; // 错误 ,

i 不是常量 Int32[] z = new Int32[3] {0, 1, 2, 3}; //

错误 , 维度长度和一个数组初始值设定项不匹配

Page 14: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 14

8.2 数组与循环控制处理8.2.1 数组2 .多维数组 数组类型的维数也称为数组类型的秩 (rank) ,它是

数组类型方括号之间的逗号个数加上 1 。例如: Int32[,]a1 = new Int32[10, 5]; // 分配一个二

维数组 Int32[,,]a2 = new Int32[10, 5, 2]; // 分配一

个三维数组 a1 数组包含 50 (10 × 5) 个元素, a2 数组包含

100 (10 × 5 × 2) 个元素。 多维数组的初始值设定项必须具有与数组维数同样多

的嵌套级别。最外面的嵌套级别对应于最左边的维度,而最里面的嵌套级别对应于最右边的维度。

Page 15: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 15

8.2 数组与循环控制处理8.2.1 数组3 .交错数组 数组的元素类型不仅可以是 .NET 平台下支持

的任意数据类型任意类型,还可以是数组类型。数组元素的类型为数组时称之为交错数组 (jagged array) ,此时元素数组的长度不必全都相同。下面的示例分配一个由 Int32 数组组成的数组:

Int32[][] a = new Int32[3][]; a[0] = new Int32[10]; a[1] = new Int32[5]; a[2] = new Int32[7];

Page 16: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 16

8.2 数组与循环控制处理

8.2.1 数组3 .交错数组

a[0] = new Int32[]{ 2,4,6,8,10,12,14,16,18,20 }; //10 个整数组成的数组

a[1] = new Int32[]{ 1,3,5,7,9 }; //5 个整数组成的数组

a[2] = new Int32[]{ 11,22,33,44,55,66,77 }; //7 个整数组成的数组。

Page 17: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 17

8.2 数组与循环控制处理

8.2.2 循环控制结构 循环控制结构可以用于重复执行嵌入语

句。 C# 中的循环(迭代)语句有: while 语句 do 语句 for 语句 foreach 语句

Page 18: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 18

8.2 数组与循环控制处理8.2.2 循环控制结构1 .while 语句 while 语句按不同条件不执行或至少执行一次语句块。 while 语句的一般格式为:

while ( 布尔表达式 ) { 语句块; }

while 语句按下列规则执行:① 计算布尔表达式。② 当布尔表达式值为 true 时,执行 while 语句中的语句块,

然后程序转到①。③ 当布尔表达式值为 false 时,结束循环。

Page 19: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 19

8.2 数组与循环控制处理8.2.2 循环控制结构1 .while 语句 下面的控制台应用程序,利用 while 语句求

1+2+3+…+10 ,并在控制台上输出其和。代码如下: using System; class Sum { static void Main() { Int32 num=1,sum=0; while (num<11) { sum=sum+num; num++; } Console.WriteLine("1+2+3+...+10 ="+sum); } }

输出结果如下:1+2+3+...+10 =55

Page 20: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 20

8.2 数组与循环控制处理8.2.2 循环控制结构2 . do 语句 do 语句按不同条件至少执行一次或多次语句块。 do 语句的一般格式为:

do { 语句块; } while (布尔表达式 ) ;

do 语句按下列规则执行:① 执行语句块一次。② 计算布尔表达式的值,当值为 true 时,程序转到①;否则,结束循环。

Page 21: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 21

8.2 数组与循环控制处理8.2.2 循环控制结构 下面的控制台应用程序,利用 do…while 语句求

1+2+3+…+10 ,并在控制台上输出其和。代码如下: using System; class Sum { static void Main() { Int32 num=1,sum=0; do { sum=sum+num; num++; } while (num<11); Console.WriteLine("1+2+3+...+10 ="+sum); } }

输出结果同 while 语句。

Page 22: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 22

8.2 数组与循环控制处理8.2.2 循环控制结构3 . for 语句 for 语句计算一个初始化表达式,然后,当某个条件

为真时,重复执行相关的嵌入语句并计算一个迭代表达式序列。 for 语句的一般格式为:

for( 初始化表达式 ; 终止条件布尔表达式 ; 步进语句表达式 )

{ 语句块; }

其中初始化表达式是为循环变量赋初值,可以有 1 个或多个,若有多个则用逗号隔开;终止条件布尔表达式是用来决定是否执行语句块;步进语句表达式是按规律改变初始表达式中循环变量的值。这三个表达式都是可选的,缺省某个表达式时,其后的“;”不能省。

Page 23: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 23

8.2 数组与循环控制处理8.2.2 循环控制结构3 . for 语句 下列代码表达了三个表达式都缺省的情况:

for(;;) { 语句块; }

for 语句按如下规则执行: ① 执行初始化表达式,为循环变量赋初值。 ② 若没有终止条件布尔表达式,或终止条件布尔表达式值为 true 时,则直接执行大括号中的语句块,程序转向③;否则,结束循环。

③ 执行步进语句表达式,程序转向②。

Page 24: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 24

8.2 数组与循环控制处理8.2.2 循环控制结构3 . for 语句 下面的控制台应用程序,利用 for 语句求 1+2+3+…

+10 ,并在控制台上输出其和。代码如下: using System; class Sum { static void Main() { Int32 num,sum; for(num=1,sum=0;num<11;num++)

{ sum=sum+num; } Console.WriteLine("1+2+3+...+10 ="+sum); } }

输出结果同 while 语句。

Page 25: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 25

8.2 数组与循环控制处理8.2.2 循环控制结构4 . foreach 语句 foreach 语句用于遍历一个集合的元素,并对该集

合中的每个元素执行一次相关的语句块。 foreach 语句的一般格式为:

foreach ( 类型标识符 标识符 in 表达式 ) { 语句块 ; }

其中类型标识符和标识符用来声明变量,表达式的类型必须是集合类型,如果该表达式的值为 null ,则将引发异常。每执行一次语句块,循环变量就依次取集合中的一个元素代入其中。

Page 26: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 26

8.2 数组与循环控制处理8.2.2 循环控制结构4 . foreach 语句 下面的控制台应用程序,用于按照元素的顺序打印出一个二维数组中的各个元素的值。代码如下:

using System; class Test { static void Main() { Double[,] values = {{1.2, 2.3, 3.4, 4.5},{5.6,

6.7, 7.8, 8.9}}; foreach (Double elementValue in values) Console.Write(" " + elementValue); Console.WriteLine(); } }

输出结果如下: 1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9

Page 27: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 27

8.2 数组与循环控制处理8.2.3 跳转语句 跳转语句用于无条件地在程序间转移控制权。 C# 中的跳转语句有:

break 语句 continue 语句 goto 语句 return 语句 throw 语句

跳转语句会将控制转到某个位置,这个位置就称为跳转语句的目标 (target) 。

当一个跳转语句出现在某个块内,而该跳转语句的目标在该块之外时,就称该跳转语句退出该块。虽然跳转语句可以将控制转到一个块外,但它永远不能将控制转到一个块的内部。

Page 28: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 28

8.2 数组与循环控制处理8.2.3 跳转语句1 . break 语句 break 语句直接退出所属的 switch、while、 do、

for 或 foreach 语句。当程序遇到这一语句后,执行紧接在被终止执行的语句后面的语句。通常break 语句总是与 if 语句联在一起。即满足条件时便跳出循环。

当多个 switch、while、 do、 for 或 foreach 语句彼此嵌套时, break 语句只应用于最里层的语句。若需要穿越多个嵌套层,可使用 goto 语句。

break 语句不能退出 finally 块。当 break 语句出现在 finally 块中时,该 break 语句的目标必须位于同一个 finally 块中,否则将发生编译时错误。块外,但它永远不能将控制转到一个块的内部。

Page 29: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 29

8.2 数组与循环控制处理8.2.3 跳转语句1 . break 语句 下面的控制台应用程序计算 1 ~ 100 之间的和 ,

当数超过 100 时终止循环。代码如下: using System; class Sum { static void Main() { Int32 num=1,sum=0; while (true) { sum=sum+num; num++; if (num>100) break; } Console.WriteLine("1+2+3+...+100

="+sum); } }

输出结果如下:1+2+3+...+100

=5050

Page 30: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 30

8.2 数组与循环控制处理8.2.3 跳转语句2 . continue 语句 continue 语句直接结束封闭它的 while、 do、 for 或 foreach 语句的本次循环,进入下一轮循环。它与前面提到的 break 语句不同,它并不终止整个循环的执行,而仅仅终止当前这一次循环的运行。

如果 continue 语句不是由 while、 do、 for 或 foreach 语句所封闭的,则发生编译时错误。

当多个 while、 do、 for 或 foreach 语句互相嵌套时, continue 语句只应用于最里层的那个语句。若需要穿越多个嵌套层,可使用 goto 语句。

continue 语句不能退出 finally 块。当 continue 语句出现在 finally 块中时,该 continue 语句的目标必须位于同一个 finally 块中,否则将发生编译时错误。

Page 31: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 31

8.2 数组与循环控制处理8.2.3 跳转语句2 . continue 语句 下面的控制台应用程序计算数 1 ~ 100 之间的偶

数和。代码如下: using System; class Sum { static void Main() { Int32 num,sum=0; for(num=1;num<101;num++) { if (num%2!=0) continue; sum=sum+num; } Console.WriteLine("1到 100 之间的偶数和为

"+sum); } }

输出结果如下:1 到 100 之间的偶数和为

2550

Page 32: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 32

8.2 数组与循环控制处理8.2.3 跳转语句3 . goto 语句 goto 语句将控制无条件的转移到由标签标记的语句。

它能用来跳出循环和 switch 语句。 如果当前函数成员中不存在具有给定名称的标签,或者如果 goto 语句不在该标签的范围内,则发生编译时错误。标号与 goto 语句必须处在同一个函数中。此规则允许使用 goto 语句将控制转移“出”嵌套范围,但是不允许将控制转移“进”嵌套范围。

goto 语句不能退出 finally 块。当 goto 语句出现在 finally 块中时,该 goto 语句的目标必须位于同一个 finally 块中,否则将发生编译时错误。

Page 33: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 33

8.2 数组与循环控制处理8.2.3 跳转语句3 . goto 语句 下面是一个控制台应用程序示例:

using System; class Test { static void Main(string[] args) { string[,] table = {{"Red", "Blue", "Green"},

{"Monday", "Wednesday", "Friday"}}; foreach (string str in table) { int row, colm; for (row = 0; row <= 1; ++row) for (colm = 0; colm <= 2; ++colm) if (str == table[row,colm]) goto done;

Page 34: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 34

8.2 数组与循环控制处理8.2.3 跳转语句 3 . goto 语句

Console.WriteLine(“{0} 未找到” , str);//显示 str 的内容未找到 continue; done: Console.WriteLine("在 [{1}][{2}] 位置找到 {0}", str, row, colm); } } }

输出结果如下: 在 [0][0] 位置找到 Red 在 [0][1] 位置找到 Blue 在 [0][2] 位置找到 Green 在 [1][0] 位置找到 Monday 在 [1][1] 位置找到 Wednesday 在 [1][2] 位置找到 Friday

Page 35: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 35

8.2 数组与循环控制处理8.2.3 跳转语句 4 . return 语句 return 语句将控制返回到包含 return 语句的函数

成员的调用方。 若函数成员没有返回类型,则 return 语句后不带任何表达式;或函数成员有返回类型,则 return 语句后的表达式的计算结果,必须与函数成员返回类型一致。

return 语句出现在 finally 块中会造成编译时错误。

下面是一个控制台应用程序示例: using System; class Test { static Int64 sum(Int32 num)

Page 36: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 36

8.2 数组与循环控制处理8.2.3 跳转语句 4 . return 语句

{ Int64 mysum=0; for (Int32 i = 1; i <=num; i++) mysum = mysum + i; return mysum; } static void Main(string[] args) { Console.WriteLine("从 1 到 100

的和为 "+sum(100)); } }

输出结果如下:从 1 到 100 的和为 50505 . throw 语句 throw 语句引发一个异常。

Page 37: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 37

8.3 数据类型的转换

类型转换是将数据从一种类型更改为另一种类型的过程。例如,可以将字符串“ 1234”转换为一个数字。可以将任意类型的数据转换为 String 类型。

某些类型转换永远不会成功。例如,字符串 " 张三 "不能转换为整型数据。

Page 38: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 38

8.3 数据类型的转换

1 .基本概念 类型转换有可能扩大,也有可能收缩。 扩大转换就是指将数据类型 A 的值转换

为数据类型 B,并且保证数据类型 B可以容纳数据类型 A 的任何可能值,例如,转换 Int32 型为 Int64 型,转换派生类型为基类型。

收缩转换就是指将数据类型 A 的值转换为数据类型 B,但数据类型 B 无法容纳数据类型 A 的某些可能值,例如,转换Int64 型为 Int32 型,转换基类型为派生类型。

Page 39: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 39

8.3 数据类型的转换

1 .基本概念 扩大转换永远不会溢出,并且总是成功

的;而收缩转换必然往往伴有信息的丢失,并有可能失败。

两种转换类型都可以是显式(使用数据类型标识符)或隐式(不使用数据类型标识符)的。例如:

Int32 a = 123; Int64 b = a; // 隐式转换 Int32 c = (Int32) b; // 显式转换

Page 40: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 40

8.3 数据类型的转换

1 .基本概念 有效的显式转换即使会导致信息的丢失,

也始终是成功的。而隐式转换只有在转换过程不丢失数据的情况下才能成功;否则,它们就会失败并生成编译或运行时错误。

.NET 类库中的 Form 窗体类有一个属性 Controls ,这是一个集合,其中元素是窗体上的所有控件,如: TextBox 。窗体上的控件都以 Control 为基类。

Page 41: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 41

8.3 数据类型的转换

1 .基本概念 下面代码将窗体上的一般控件显式收缩转

换为 TextBox 控件。 foreach(Control ctl in Controls) { //从 Control 基类显式转变为 TextBox派

生类 TextBox tx = (TextBox)ctl; }

执行中许多非 TextBox 控件向 TextBox控件转换时会失败。

Page 42: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 42

8.3 数据类型的转换

1 .基本概念 当原始数据类型在目标转换类型中没有明显

的对应类型时,就会发生丢失数据的转换。例如,字符串 "Fred" 不能转换为一个数字。在这些情况下,类型转换函数将返回一个默认值。对于字符串类型,默认值为 "";对于整型类型,默认值为数字 0 。

常用的 ToString方法就是显式转换的典型代表,因为它是所有数据类型的根类 object的方法,所以所有数据类型都可以向字符串类型转换。

Page 43: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 43

8.3 数据类型的转换

2 . Convert 类 Convert 是一个专用来将一个基本数据类

型转换为另一个基本数据类型的类,因为是静态类,不需要实例化就可以直接使用。

例如: Int64 I = 123; Int32 i = Convert.ToInt32(I);

Page 44: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 44

8.3 数据类型的转换

3 .装箱和拆箱 装箱和拆箱的概念是 C# 的类型系统的核心。它在值类型和引用类型之间的架起了一座桥梁,使得任何值类型的值都可以转换为 object 类型的值,反过来转换也可以。从值类型转换为引用类型称为装箱,反之,称为拆箱。

装箱和拆箱使我们能够统一地来考察类型系统,其中任何类型的值最终都可以按对象处理

Page 45: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 45

8.3 数据类型的转换

3 .装箱和拆箱 下面是装箱和拆箱转换的示例,代码如下:

Int32 i = 10; //i 是值类型 object o = i; //装箱 i = (Int32)o; //拆箱 MessageBox.Show(i.ToString());// 整型

数转换成字符串 装箱操作如图 8-2 所示 ,拆箱操作如图 8-3 所

示。

Page 46: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 46

8.3 数据类型的转换

3 .装箱和拆箱 图 8-2装箱操作 图 8-3拆箱操作

i: Int32

10

i: Int32

10

o: object

拆箱

i: Int32

10

Int32

10o:object

装箱

Page 47: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 47

8.3 数据类型的转换

3 .装箱和拆箱 一个装箱操作包括两个步骤:首先分配

一个对象实例,然后将值类型的值复制到该实例中。

一个拆箱操作包括两个步骤:首先检查对象实例是否为给定值类型的一个装了箱的值,然后将该值从实例中复制出来。

Page 48: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 48

8.4 改造 ShowDialog方法

我们已经建立了数据维护对象体系,如图 8-4 所示。

Page 49: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 49

8.4 改造 ShowDialog方法

实现了 frm 增改学生的 ShowDialog方法。

类似地,要为 frm 增改课程等实现ShowDialog方法。不仅工作量较大,且容易出错,将来也不利于进行代码维护。

若能在 frm 增改中实现 ShowDialog方法,则可以惠及其派生类,起到“一劳永逸”的功效。

Page 50: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 50

8.4 改造 ShowDialog方法

8.4.1 提示必要信息 在 frm 增改中实现 ShowDialog方法所

面临的最大问题是:不知道其派生类中需要处理的输入控件。而处理的关键是要抓住被处理的控件。

窗体对象包含有一个控件集合 Controls ,控件集合 Controls 中包含了窗体上所有的控件( Control ),如 TextBox和DateTimePicker 控件等。如果能对Controls 中所有的 Control 进行遍历,就能进行适当的处理了。

Page 51: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 51

8.4 改造 ShowDialog方法

8.4.1 提示必要信息 像 foreach这样的循环控制结构可以有效地解决遍历

问题。下面是完成后的 frm 增改的 ShowDialog方法。

public virtual void ShowDialog(DataGridView dgv区域 ,Boolean bAdd )

{ …… // 循环处理当前窗体上所有输入控件 foreach (Control ctl in Controls) { // 初始化输入控件的内容 String str 控件类型 =ctl.Name.ToString().Substring(0,

3);//前三个字符反映控件类型 switch (str 控件类型 ) { case "txt": case "cmb": case "dtp":

Page 52: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 52

8.4 改造 ShowDialog方法

8.4.1 提示必要信息

if (bAdd) //清空各个输入对象 ctl.Text = null; else { //保证有记录可以修改 if (dgv区域 .RowCount <= 0) { MessageBox.Show("无记录可以修

改! "); return; }

Page 53: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 53

8.4 改造 ShowDialog方法

8.4.1 提示必要信息 //根据所选记录初始化输入对象 // 控件类型字符后面为控件名称,恰好为数据区域栏目名称和数据库字段名称

String str 控件名称 = ctl.Name.ToString().Substring(3);

ctl.Text = dgv区域 .CurrentRow.Cells[str 控件名称 ].Value.ToString();

} break; } } //调出模式对话框 ShowDialog(); }

Page 54: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 54

8.4 改造 ShowDialog方法

8.4.2 控制文本输入长度 不论是增加还是修改操作,其结果都要存入

数据库。若输入的数据长度超过了实际数据库对应字段的长度,则会出现异常。所以有必要对所有输入控件设置符合要求的可输入长度。例如,把 TextBox文本控件的MaxLength 属性值设置为实际数据库对应字段的长度。有两种方法可以实现: 一种是在控件所在窗体类(如 frm 增改学生)

中进行设置。 一种是在控件所在窗体类的基类(如 frm 增

改)中进行设置。

Page 55: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 55

8.4 改造 ShowDialog方法

8.4.2 控制文本输入长度 前一种方法需要对每一个窗体的控件进行修改,效

率不高,后一种方法优势是明显的。 专门设计一个方法 SetMaxLength ,根据数据库

表中字符串字段和数值字段的大小来设置 TextBox和 ComboBox的MaxLength 属性,在 frm 增改的 ShowDialog 中调用。

虽然TextBox、 ComboBox、 DateTimePicker和CheckBox 等控件的基类都是 Control ,但只有TextBox和 ComboBox有MaxLength 属性,可以对 Control 集合进行迭代处理,然后进行从Control向 TextBox或 ComboBox 的转换。

Page 56: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 56

8.5 改造 Modify 方法

8.5.1 更新数据库 更新数据库的代码见 P143 上重写的

Modify()方法,关键是遍历每一个Control 控件,形成标准的 Insert或Update 语句。

Page 57: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 57

8.5 改造 Modify 方法

8.5.2 刷新浏览数据

增加和修改的结果已经存入了数据库,还需要及时地反映在浏览对象中供用户参考。因为 DataGridView 控件是和 DataSet 中的一个表绑定的,所以只要修改 DataSet 中的表就可以达到目标。

Page 58: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 58

8.6 隐藏浏览对象中的指定栏目

frm浏览已经可以将相关数据展现出来了。美中不足的是,起表间关联作用的主键和外键(含有 ID 的字段,例如,学生 ID )也显示出来了。对用户而言这是不需要的。

将隐藏 ID栏目的函数命名为 HideIDColumns ,通过DataGridView 类型的参数“ dgv区域”传递要处理的区域。检查“ dgv区域”中的每一个栏目,若栏目的名称含有 ID 字样,则使其不可见。

Page 59: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 59

8.6 隐藏浏览对象中的指定栏目

/// <summary> /// 将带 ID 的字段隐藏起来 /// </summary> /// <param name="dgv区域 "></param> private void HideIDColumns(DataGridView dgv区域 ) { if (dgv区域 .DataMember != "") { //检查每一个栏目,若栏目的名字含有 ID 字样,则隐藏 foreach (DataGridViewColumn clmn in dgv区域 .Columns)

if (clmn.Name.IndexOf("ID") >= 0) clmn.Visible = false; } }

Page 60: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 60

8.6 隐藏浏览对象中的指定栏目

调用 HideIDColumns 过程的时机是上、下两个区域绑定的数据成员变化时。 //" 上区域 "显示的数据表变化时自动执行 private void dgv 上区域 _DataMemberChanged(object sender,

EventArgs e) { HideIDColumns(dgv 上区域 );// 将带 ID 的字段隐藏起来 } //" 下区域 "显示的数据表变化时自动执行 private void dgv 下区域 _DataMemberChanged(object sender,

EventArgs e) { HideIDColumns(dgv 下区域 );// 将带 ID 的字段隐藏起来 }

Page 61: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 61

习 题

一、简答题 1 .循环控制结构有几种?各有什么特

点? 2 .如果事先知道循环次数,选用哪种

循环结构比较好? 3 .在什么场合使用数组比较好? 4 .在系统代码中找出数据转换的例子,

指出是隐式转换还是显示转换,是扩大转换还是收缩转换。

Page 62: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 62

习 题二、操作题1 . frm 登录通过输入账户(用户名和密码)来验证用户的合法性,同时为合法用户提供修改密码的能力。设计并实现 frm 登录类。

2 .将 frm 增改中将修改内容反映在浏览的 dgv区域中的 foreach代码改为等价的 for代码。

// 将修改内容反映在浏览的 dgv区域中 foreach (Control ctl in Controls) { //前三个字符反映控件类型 String str 控件类型 =

ctl.Name.ToString().Substring(0, 3); switch (str 控件类型 )

Page 63: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 63

习 题

二、操作题 { case "txt": case "cmb": case "dtp": // 控件类型字符后面为控件名称,恰好为数据区域栏目名称和数据库字段名称 String str 字段名 = ctl.Name.ToString().Substring(3); ds.Tables[dgv区域 .DataMember].Rows[dgv区域 .CurrentRow.Index] [str 字段名 ]=ctl.Text; break; } }

Page 64: Visual C#.NET 程序设计

第 8 章 维护数据 ( 二 )

23/4/21 64

习 题

二、操作题3 .编码实现 8.4.2小节要求的控制文本

输入长度的 SetMaxLength方法,并通过 frm 增改的 ShowDialog方法调用。