第13章C#高级特性_第1页
第13章C#高级特性_第2页
第13章C#高级特性_第3页
第13章C#高级特性_第4页
第13章C#高级特性_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

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

文档简介

1、第第13章章C#高级特性高级特性13.1 泛泛 型型13.2 反反 射射13.3 多线程程序设计多线程程序设计 13.1 泛泛 型型13.1.1 什么是泛型什么是泛型所谓泛型,是指通过参数化类型来实现在同一份代码所谓泛型,是指通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型参数化类型”将类型抽象化,从而实现更为灵活的复用。将类型抽象化,从而实现更为灵活的复用。泛型类型和普通类型的区别在于泛型类型与一组类型参数泛型类型和普通类型的区别在于泛型类型与一组类型参数或类型变量关联。或类型变量关联。C#泛型能

2、力是由泛型能力是由CLR在运行时支持,区别于在运行时支持,区别于C+的编的编译时模板机制和译时模板机制和Java的编译时的的编译时的“搽拭法搽拭法”。这使得泛型。这使得泛型能力可以在各个支持能力可以在各个支持CLR的语言之间进行无缝的互操作。的语言之间进行无缝的互操作。数据的抽象:数据的抽象:int MAX(int a,int b) return ab?a:b; double MAX1(double a,double b) return ab?a:b; int MAX(int a,int b) return ab?a:b; double MAX(double a,double b) retur

3、n ab?a:b; 重载重载数据类型的抽象:数据类型的抽象: T MAX(T a,T b) return ab?a:b; 泛型泛型13.1.2 泛型的声明和使用泛型的声明和使用通常先声明泛型,然后通过类型实例化来使用泛型。通常先声明泛型,然后通过类型实例化来使用泛型。定义泛型的语法格式如下:定义泛型的语法格式如下:访问修饰符访问修饰符返回类型返回类型 泛型名称泛型名称其中,其中,“泛型名称泛型名称”要符合标识符的定义。尖括号要符合标识符的定义。尖括号表示类型参数列表,可以包含一个或多个类型参数,如表示类型参数列表,可以包含一个或多个类型参数,如。C#中常用的泛型有泛型类和泛型方法,例如:中常用

4、的泛型有泛型类和泛型方法,例如:class Stack/声明泛型类声明泛型类 T dataMaxSize;int top;void swap(ref T a,ref T b)/定义泛型方法定义泛型方法 T tmp = a;a = b;b = tmp;【例【例13.0】 分析以下程序执行结果。分析以下程序执行结果。 public class abc public A a; public B b; public void show() MessageBox.Show(a.ToString() + ,+b.ToString(); private void button2_Click(object s

5、ender, EventArgs e) abc a = new abc(); a.a = 2; a.b = 3.8; a.show(); 【例【例13.1】 分析以下程序的执行结果。分析以下程序的执行结果。using System;namespace Proj13_1class Stack/声明栈泛型类声明栈泛型类int maxsize;/栈中元素最多个数栈中元素最多个数T data;/存放栈中存放栈中T类型的元素类型的元素int top;/栈顶指针栈顶指针public Stack()/构造函数构造函数maxsize = 10;data = new Tmaxsize;top = -1;publ

6、ic Stack(int n)/重载构造函数重载构造函数maxsize = n;data = new Tmaxsize;top = -1;public bool StackEmpty()/判断栈空方法判断栈空方法 return top = -1; public bool Push(T e)/元素元素e进栈方法进栈方法 if (top = maxsize - 1)/栈满返回栈满返回false return false; top+; datatop = e; return true; public bool Pop(ref T e) /元素出栈方法元素出栈方法 if (top = -1)/栈空返回

7、栈空返回false return false; e = datatop; top-; return true; class Program static void Main(string args) int e = 0; Stack s = new Stack();/定义整数栈定义整数栈 s.Push(1);/进栈进栈3个整数个整数 s.Push(3); s.Push(2); Console.Write(整数栈出栈次序:整数栈出栈次序:); while (!s.StackEmpty()/栈不空时出栈元素栈不空时出栈元素 s.Pop(ref e); Console.Write(0 , e); C

8、onsole.WriteLine(); string e1 = ;Stack s1 = new Stack(); /定义字符串栈定义字符串栈s1.Push(Mary);/进栈进栈3个字符串个字符串s1.Push(John);s1.Push(Simth);Console.Write(字符串栈出栈次序:字符串栈出栈次序:);while (!s1.StackEmpty()/栈不空时出栈元素栈不空时出栈元素 s1.Pop(ref e1); Console.Write(0 , e1);Console.WriteLine(); 本程序先声明了一个泛型栈本程序先声明了一个泛型栈Stack,然后实例化为,然后

9、实例化为整数栈整数栈s和字符串栈和字符串栈s1,各自进栈,各自进栈3个元素后并出栈,程序个元素后并出栈,程序执行结果如图执行结果如图13.1所示。所示。13.2 反反 射射13.2.1 反射概述反射概述反射是一种机制,通过这种机制可以知道一个未知类反射是一种机制,通过这种机制可以知道一个未知类型的类型信息。型的类型信息。例如有一个对象,它不是我们定义的,既可能是通过例如有一个对象,它不是我们定义的,既可能是通过网络捕捉到的,也可能是使用泛型定义的,但我们想知道网络捕捉到的,也可能是使用泛型定义的,但我们想知道这个对象的类型信息,想知道这个对象有哪些方法或者属这个对象的类型信息,想知道这个对象有

10、哪些方法或者属性什么的,甚至想进一步调用这个对象的方法。关键是现性什么的,甚至想进一步调用这个对象的方法。关键是现在只知道它是一个对象,不知道它的类型,自然不会知道在只知道它是一个对象,不知道它的类型,自然不会知道它有哪些方法等信息,这时该怎么办呢?它有哪些方法等信息,这时该怎么办呢?反射机制就是解决这么一个问题的,通过反射机制就反射机制就是解决这么一个问题的,通过反射机制就可以知道未知类型对象的类型信息。可以知道未知类型对象的类型信息。反射提供了封装程序集、模块和类型的对象(反射提供了封装程序集、模块和类型的对象(Type类类型),可以使用反射动态创建类型的实例,将类型绑定到型),可以使用反

11、射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。们进行访问。归纳起来,反射在下列情况下很有用:归纳起来,反射在下列情况下很有用:l 需要访问程序元数据的属性。需要访问程序元数据的属性。l 检查和实例化程序集中的类型。检查和实例化程序集中的类型。l 在运行时构建新类型。在运行时构建新类型。l 执行后期绑定,访问在运行时创建的类型的方法。执行后期绑定,访问在运行时创建的类型的方法。13.2.2 反射中常

12、用的类反射中常用的类1. Type类类System.Reflection是反射的命名空间,而是反射的命名空间,而Type类为类为System.Reflection功能的根,也是访问元数据的主要方式。功能的根,也是访问元数据的主要方式。Type类表示类型声明,包括类类型、接口类型、数组类表示类型声明,包括类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。及开放或封闭构造的泛型类型。公共属性公共属性说明说明IsAbstract获取一个值,通过该值指示获取一个值,通过该值指示Type是否为抽象的并且必

13、须被重是否为抽象的并且必须被重写写IsArray获取一个值,通过该值指示获取一个值,通过该值指示Type是否为数组是否为数组IsByRef获取一个值,通过该值指示获取一个值,通过该值指示Type是否由引用传递是否由引用传递IsClass获取一个值,通过该值指示获取一个值,通过该值指示Type是否是一个类,即不是值类是否是一个类,即不是值类型或接口型或接口IsInterface获取一个值,通过该值指示获取一个值,通过该值指示Type是否为接口,即不是类或值是否为接口,即不是类或值类型类型IsSubclassOf确定当前确定当前Type表示的类是否是从指定的表示的类是否是从指定的Type表示的类派

14、生的表示的类派生的MakeArrayType返回一个表示当前类型的一维数组(下限为零)的返回一个表示当前类型的一维数组(下限为零)的Type对象对象Module获取在其中定义当前获取在其中定义当前Type的模块的模块Name获取当前成员的名称获取当前成员的名称Namespace获取获取Type的命名空间的命名空间ReflectedType获取用于获取该成员的类对象获取用于获取该成员的类对象Type类的属性类的属性方法方法说明说明GetElementType当在派生类中重写时,返回当前数组、指针或引用类型包含的当在派生类中重写时,返回当前数组、指针或引用类型包含的或引用的对象的或引用的对象的Ty

15、peGetEvent获取由当前获取由当前Type声明或继承的特定事件声明或继承的特定事件GetEvents获取由当前获取由当前Type声明或继承的事件声明或继承的事件GetField获取当前获取当前Type的特定字段的特定字段GetFields获取当前获取当前Type的字段的字段GetInterface获取由当前获取由当前Type实现或继承的特定接口实现或继承的特定接口GetInterfaces当在派生类中重写时,获取由当前当在派生类中重写时,获取由当前Type实现或继承的所有接口实现或继承的所有接口GetMember获取当前获取当前Type的指定成员的指定成员GetMembers获取当前获取

16、当前Type的成员(包括属性、方法、字段、事件等)的成员(包括属性、方法、字段、事件等)GetMethod获取当前获取当前Type的特定方法的特定方法GetMethods获取当前获取当前Type的方法的方法GetProperties获取当前获取当前Type的属性的属性GetProperty获取当前获取当前Type的特定属性的特定属性InvokeMember使用指定的绑定约束并匹配指定的参数列表,调用指定成员使用指定的绑定约束并匹配指定的参数列表,调用指定成员Type类的方法类的方法归纳起来,得到一个归纳起来,得到一个Type实例的三种方法如下:实例的三种方法如下:(1)使用)使用System.

17、Object.GetType(),例如:,例如:Person pe=new Person();/定义定义pe为为person类的一个对象类的一个对象Type t=pe.GetType();这样这样t为为pe的的Type对象。对象。(2)使用)使用System.Type.GetType()静态方法,参数为静态方法,参数为类型的完全限定名。例如:类型的完全限定名。例如:Type t=Type.GetType(MyNs.Person);其中,其中,MyNs.Person为为MyNs命名空间中的命名空间中的Person类,类,这样这样t为该类的为该类的Type对象。对象。(3)使用)使用typeof运

18、算符,例如:运算符,例如:Type t=typeof(Person);其中其中Person为一个类,这样为一个类,这样t为该类的为该类的Type对象。对象。2. System.Reflection反射命名空间反射命名空间System.Reflection反射命名空间包含提供加载类型、反射命名空间包含提供加载类型、方法和字段的有组织的视图的类和接口,具有动态创建方法和字段的有组织的视图的类和接口,具有动态创建和调用类型的功能。其中主要的类及其功能如下:和调用类型的功能。其中主要的类及其功能如下:l Assembly类类:通过它可以加载、了解和操作一个程:通过它可以加载、了解和操作一个程序集。序集

19、。l AssemblyName类类:通过它可以找到大量隐藏在程:通过它可以找到大量隐藏在程序集的身份中的信息,如版本信息、区域信息等。序集的身份中的信息,如版本信息、区域信息等。l ConstructorInfo类类:用于发现构造函数及调用构造:用于发现构造函数及调用构造函数。通过对函数。通过对ConstructorInfo调用调用Invoke来创建对来创建对象,其中象,其中ConstructorInfo是由是由Type对象的对象的GetConstructors或或GetConstructor方法返回的。方法返回的。l EventInfo类类:通过它可以找到事件的信息。:通过它可以找到事件的信

20、息。l FieldInfo类类:通过它可以找到字段的信息。:通过它可以找到字段的信息。l MethodInfo类类:通过它可以找到方法的信息。:通过它可以找到方法的信息。l ParameterInfo类类:通过它可以找到参数的信息。:通过它可以找到参数的信息。l PropertyInfo类类:通过它可以找到属性的信息。:通过它可以找到属性的信息。l MemberInfo类类:它是一个抽象基类,为:它是一个抽象基类,为EventInfo、FieldInfo、MethodInfo、PropertyInfo等类型定义了等类型定义了公共的行为。公共的行为。l Module类类:用来访问带有多文件程序集

21、的给定模块。:用来访问带有多文件程序集的给定模块。l DefaultMemberAttribute类类:定义某类型的成员,该:定义某类型的成员,该成员是成员是InvokeMember使用的默认成员。使用的默认成员。 公共属性公共属性说明说明EntryPoint获取此程序集的入口点获取此程序集的入口点FullName获取程序集的显示名称获取程序集的显示名称Location获取包含清单的已加载文件的路径或位置获取包含清单的已加载文件的路径或位置ManifestModule获取包含当前程序集清单的模块获取包含当前程序集清单的模块其中重要的其中重要的Assembly类,它的常用属性和常用方法类,它的常

22、用属性和常用方法如下。如下。Assembly类的常用属性类的常用属性 方法方法说明说明GetFiles获取程序集清单文件表中的文件获取程序集清单文件表中的文件GetModule获取此程序集中的指定模块获取此程序集中的指定模块GetModules获取作为此程序集的一部分的所有模块获取作为此程序集的一部分的所有模块GetType获取表示指定类型的获取表示指定类型的Type对象对象GetTypes获取此程序集中定义的类型获取此程序集中定义的类型LoadFile加载程序集文件的内容加载程序集文件的内容LoadFrom在已知程序集的文件名或路径等信息时加载程序集在已知程序集的文件名或路径等信息时加载程序

23、集LoadModule加载此程序集的内部模块加载此程序集的内部模块Assembly类的常用方法类的常用方法 13.2.3 反射的应用示例反射的应用示例1. 通过反射查看类型的成员信息通过反射查看类型的成员信息查看类型信息的过程如下:查看类型信息的过程如下:(1)获取指定类型的一个)获取指定类型的一个Type对象或对象或Type对象数组。对象数组。(2)通过)通过Type类的许多方法来发现与该类型的成员有类的许多方法来发现与该类型的成员有关的信息。关的信息。【例【例13.2】 编写一个程序,通过反射输出编写一个程序,通过反射输出System.Object类的方法、字段和构造函数的信息。类的方法、

24、字段和构造函数的信息。解解:先通过:先通过Type的的GetTypes()方法获取方法获取System.Object类类的的Type对象对象t,然后用,然后用Type类的类的GetMethods()、GetFields()、GetConstructors()分别获取分别获取t对象的方法、字段和构造函数信对象的方法、字段和构造函数信息并输出。程序如下:息并输出。程序如下:using System;using System.Reflection;namespace Proj8_2class Programstatic void Main(string args) string classname

25、= System.Object;Console.WriteLine(0类类,classname);Type t = Type.GetType(classname);MethodInfo m = t.GetMethods();Console.WriteLine( 0的方法个数的方法个数:1, t.FullName, m.Length);foreach(MethodInfo item in m) Console.WriteLine(t0 ,item.Name); FieldInfo f = t.GetFields(); Console.WriteLine( 0的字段个数的字段个数:1, t.Ful

26、lName, f.Length); foreach (FieldInfo item in f) Console.WriteLine(t0 , item.Name); ConstructorInfo c = t.GetConstructors();Console.WriteLine( 0的构造函数个数的构造函数个数:1, t.FullName, c.Length);foreach (ConstructorInfo item in c)Console.WriteLine(t0 , item.Name); 程序执行结果程序执行结果2. 通过反射调用未知类的某方法通过反射调用未知类的某方法调用未知类的

27、某方法的过程如下:调用未知类的某方法的过程如下:(1)假设一个未知类)假设一个未知类c属于某个属于某个DLL文件文件xyz.dll,采,采用用Assembly.LoadFrom(xyz.dll)加载该程序集。加载该程序集。(2)调用)调用assembly.GetTypes()方法得到一个方法得到一个Type对对象数组象数组t。(3)通过)通过Type.GetConstructor()方法得到某个对象方法得到某个对象的构造函数。的构造函数。(4)通过)通过ConstructorInfo.Invoke()方法调用构造函方法调用构造函数创建未知类的对象数创建未知类的对象s。(5)通过对象)通过对象s

28、调用某方法。调用某方法。【例【例13.3】 有一个项目有一个项目Proj8_3,通过添加代码文件模,通过添加代码文件模板向其中添加一个板向其中添加一个Sport.cs文件,该文件的内容如下:文件,该文件的内容如下:using System;public abstract class Sport/体育运动类体育运动类protected string name; /项目名项目名public abstract string GetDuration();/获取比赛时间获取比赛时间public abstract string GetName();/获取项目名获取项目名在命令行方式下使用以下命令生成在命令

29、行方式下使用以下命令生成Sport.dll文件:文件:csc/target:library Sport.cs命令行编译命令命令行编译命令 采用命令行方式对采用命令行方式对C#文件进行编译的程序是文件进行编译的程序是csc.exe,它通常位于系统目,它通常位于系统目录下的录下的Microsoft.NETFramework文件夹中,根据每台计算机上的文件夹中,根据每台计算机上的确 切 配 置 , 此 位 置 可 能 有 所 不 同 。 一 般 情 况 下 其 位 置 是确 切 配 置 , 此 位 置 可 能 有 所 不 同 。 一 般 情 况 下 其 位 置 是C:WindowsMicrosoft

30、.NETFrameworkv2.0.50727文件夹中。文件夹中。 为了进行命令行编译,在为了进行命令行编译,在Windows下运行下运行cmd命令,进入存放项目的文命令,进入存放项目的文件夹,如件夹,如H:C#2005ch8Proj8_3Proj8_3,其中包含有本项目的,其中包含有本项目的C#文件。为文件。为了能够执行了能够执行csc程序,通过程序,通过path设置路径,即在命令行方式中输入以下命令:设置路径,即在命令行方式中输入以下命令:path C:WindowsMicrosoft.NETFrameworkv2.0.50727 常用的编译命令如下:常用的编译命令如下: (1)csc/t

31、arget:library 模块名模块名 该命令使编译器创建一个动态链接库(该命令使编译器创建一个动态链接库(DLL)而不是一个可执行文件)而不是一个可执行文件(EXE)。)。 (2)csc/reference:filename 该命令导致编译器将指定文件中的该命令导致编译器将指定文件中的public类型信息导入到当前项目中,从类型信息导入到当前项目中,从而可以从指定的程序集文件引用元数据。而可以从指定的程序集文件引用元数据。filename包含程序集清单的文件的包含程序集清单的文件的名称。若要导入多个文件,请为每个文件包括一个单独的名称。若要导入多个文件,请为每个文件包括一个单独的/refe

32、rence选项。选项。同样通过添加代码文件模板向其中添加一个同样通过添加代码文件模板向其中添加一个SomeSports.cs文件,该文件的内容如下:文件,该文件的内容如下:using System;public class Basketball : Sportpublic Basketball()/篮球类篮球类name = 篮球篮球; public override string GetDuration()return 共节,每节分钟共节,每节分钟; public override string GetName()return name; public class Hockey : Sport

33、/曲棍球类曲棍球类public Hockey()name = 曲棍球曲棍球; public override string GetDuration()return 两个半场,各分钟两个半场,各分钟; public override string GetName()return name; public class Football : Sport/足球类足球类public Football()name = 足球足球; public override string GetDuration()return 两个半场,各分钟两个半场,各分钟; public override string GetNa

34、me()return name; 在命令行方式下使用以下命令生成在命令行方式下使用以下命令生成SomeSports.dll文件:文件:csc/target:library /reference:Sport.dll SomeSports.cs这样就生成两个动态链接库文件这样就生成两个动态链接库文件Sport.dll和和SomeSports.dll。现要在现要在Program类类Main中设计相应代码,根据用户选择的体育中设计相应代码,根据用户选择的体育项目输出相应的比赛时间。项目输出相应的比赛时间。解:解:由于在设计由于在设计Program.cs程序时,提供的程序时,提供的Sport.dll和和

35、SomeSports.dll都是动态链接库,不知道其中每个类是如何都是动态链接库,不知道其中每个类是如何声明的,只知道声明的,只知道GetName()和和GetDuration()两个方法的功能,两个方法的功能,为此采用反射技术。设计为此采用反射技术。设计Program.cs程序如下:程序如下:using System;using System.Reflection;namespace Proj8_3 class Programstatic void Main(string args)int i, j; if (args.GetLength(0) 1) /命令行输入的参数不正确命令行输入的参数

36、不正确Console.WriteLine(用法用法:Program dll库名库名); else Assembly assembly=Assembly.LoadFrom(args0); /获取程序集对象获取程序集对象 Type types = assembly.GetTypes(); Console.WriteLine(assembly.GetName().Name + 包含的项目名如下包含的项目名如下:);for (i = 0; i types.GetLength(0); +i)Console.WriteLine(r + i + : + typesi.Name);i = types.Leng

37、th - 1; Console.Write(请选择请选择(0- + i + ):); j = Convert.ToInt32(Console.ReadLine(); Console.WriteLine(); if (typesj.IsSubclassOf(typeof(Sport) /若若typesj是是Sport的子类的子类 ConstructorInfo ci = typesj.GetConstructor(new Type0); Sport sport = (Sport)ci.Invoke(new Object0); /创建创建sport对象对象 Console.WriteLine(sp

38、ort.GetName()+比赛时间比赛时间:+ sport.GetDuration(); else Console.WriteLine(typesj.Name + 不属于指定的体育项目不属于指定的体育项目); 在命令行中输入以下命令在命令行中输入以下命令Program.exe文件:文件:csc/reference:Sport.dll Program.cs在命令行中输入以下命令执行在命令行中输入以下命令执行Program.exe:Program SomeSports.dll程序的一次执行结果如图程序的一次执行结果如图13.3所示,在出现各种提示所示,在出现各种提示后输入后输入2,输出足球的比赛

39、时间。,输出足球的比赛时间。.dll只需知道类和方法,可只需知道类和方法,可以通过反射技术使用它。以通过反射技术使用它。以前我们必须知道一个类的完整定义,才可以使用以前我们必须知道一个类的完整定义,才可以使用这个类。这个类。采用反射技术:采用反射技术:13.3 多线程程序设计多线程程序设计13.3.1 多线程的概述多线程的概述当一个程序开始运行时,它就是一个进程。当一个程序开始运行时,它就是一个进程。进程所指包括执行中的程序和程序所使用到的内存和进程所指包括执行中的程序和程序所使用到的内存和系统资源。系统资源。而一个进程又是由多个线程所组成的,线程是程序中而一个进程又是由多个线程所组成的,线程

40、是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流,即执行同样的函数。多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。完成各自的任务。 从上图可以看出,几乎所有的进程都拥有两个以上的线程。从

41、而从上图可以看出,几乎所有的进程都拥有两个以上的线程。从而可以看出,线程是提供应用程序性能的重要手段之一,尤其在多核可以看出,线程是提供应用程序性能的重要手段之一,尤其在多核CPU的机器上尤为明显。的机器上尤为明显。 一个一个C#程序开始于一个单线程,这个单线程是被程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为和操作系统(也称为“主线程主线程”)自动创建的,并具有多)自动创建的,并具有多线程创建额外的线程。线程创建额外的线程。 在在C#应用程序中,第一个线程总是应用程序中,第一个线程总是Main()方法,因为方法,因为第一个线程是由第一个线程是由.NET运行库开始执行的,运行库开

42、始执行的,Main()方法方法是是.NET运行库选择的第一个方法。后续的线程由应用程序运行库选择的第一个方法。后续的线程由应用程序在内部启动,即应用程序可以创建和启动新的线程。在内部启动,即应用程序可以创建和启动新的线程。多线程:多线程:在同一时间执行多个任务的功能,称为多线在同一时间执行多个任务的功能,称为多线程或自由线程。程或自由线程。多线程的优点:多线程的优点:可以同时完成多个任务;可以使程序可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以没有进行处理的任

43、务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性随时停止任务;可以设置每个任务的优先级以优化程序性能。能。多线程的缺点:多线程的缺点:对资源的共享访问可能造成冲突(对对资源的共享访问可能造成冲突(对共享资源的访问进行同步或控制)共享资源的访问进行同步或控制) ;程序的整体运行速度;程序的整体运行速度减慢等等。减慢等等。13.3.2 线程命名空间线程命名空间线程命名空间是线程命名空间是System.Threading,它提供了多线程,它提供了多线程程序设计的类和接口等,用以执行诸如创建和启动线程、程序设计的类和接口等,用以执行诸如创建和启动线程、同步多个线程、

44、挂起线程和中止线程等任务。其中有关线同步多个线程、挂起线程和中止线程等任务。其中有关线程方面的类如下:程方面的类如下:l Thread类:用于创建并控制线程、设置其优先级并获取其状类:用于创建并控制线程、设置其优先级并获取其状态。态。l Monitor类:提供同步对对象的访问的机制。类:提供同步对对象的访问的机制。l Mutex类:一个同步基元,也可用于进程间同步。类:一个同步基元,也可用于进程间同步。l ThreadAbortException类:在对类:在对Abort方法进行调用时引发方法进行调用时引发的异常。无法继承此类。的异常。无法继承此类。l ThreadInterruptedExc

45、eption类:中断处于等待状态的类:中断处于等待状态的Thread时引发的异常。时引发的异常。l ThreadStartException类:当基础操作系统线程已启动但该类:当基础操作系统线程已启动但该线程尚未准备好执行用户代码前,托管线程中出现错误,则线程尚未准备好执行用户代码前,托管线程中出现错误,则会引发异常。会引发异常。l ThreadStateException类:当类:当Thread处于对方法调用无效的处于对方法调用无效的ThreadState时引发的异常。时引发的异常。13.3.3 Thread类及其应用类及其应用1. Thread类类Thread类是最重要的线程类。类是最重要

46、的线程类。属性属性说明说明CurrentThread获取当前正在运行的线程获取当前正在运行的线程IsAlive获取一个值,该值指示当前线程的执行状态获取一个值,该值指示当前线程的执行状态IsBackground获取或设置一个值,该值指示某个线程是否为后台线程获取或设置一个值,该值指示某个线程是否为后台线程Name获取或设置线程的名称获取或设置线程的名称Priority获取或设置一个值,该值指示线程的调度优先级获取或设置一个值,该值指示线程的调度优先级ThreadState获取一个值,该值包含当前线程的状态获取一个值,该值包含当前线程的状态方法方法说明说明Abort在调用此方法的线程上引发在调用

47、此方法的线程上引发ThreadAbortException,以开始终止此线,以开始终止此线程的过程。调用此方法通常会终止线程程的过程。调用此方法通常会终止线程Interrupt中断处于等待、休眠或联接状态的线程中断处于等待、休眠或联接状态的线程Join阻塞调用线程,直到某个线程终止时为止。阻塞调用线程,直到某个线程终止时为止。t.Join()可以理解为把线程可以理解为把线程t放到当前位置来执行放到当前位置来执行,只有只有t结束以后才会执行结束以后才会执行t.Join()以后的代码以后的代码 Resume继续已挂起的线程继续已挂起的线程Sleep将当前线程阻塞指定的毫秒数将当前线程阻塞指定的毫秒

48、数Start使线程得以按计划执行使线程得以按计划执行Suspend挂起线程,或者如果线程已挂起,则不起作用。挂起线程,或者如果线程已挂起,则不起作用。2. 创建和启动新线程创建和启动新线程应用程序执行时,将创建新的应用程序域。当执行环应用程序执行时,将创建新的应用程序域。当执行环境调用应用程序的入口点(境调用应用程序的入口点(Main方法)时,将创建应用程方法)时,将创建应用程序的主线程。主线程以外的线程一般称为序的主线程。主线程以外的线程一般称为工作线程工作线程。Thread类的主要构造函数如下:类的主要构造函数如下:(1)public Thread(ThreadStart start)其中

49、,参数其中,参数start为为ThreadStart委托,它表示此线程开委托,它表示此线程开始执行时要调用的方法。始执行时要调用的方法。(2)public Thread(ParameterizedThreadStart start)其中,参数其中,参数start为为ParameterizedThreadStart委托,表委托,表示此线程开始执行时要调用的方法。它表示初始化示此线程开始执行时要调用的方法。它表示初始化Thread类的新实例,并指定允许对象在线程启动时传递给线程的类的新实例,并指定允许对象在线程启动时传递给线程的委托。委托。例如,有以下类:例如,有以下类:class MyClass

50、/声明包含方法的类声明包含方法的类public void method1()/不带参数的方法不带参数的方法method1public void method2(object data) /带参数的方法带参数的方法method2采用静态方式创建和启动工作线程的过程如下:采用静态方式创建和启动工作线程的过程如下:MyClass obj = new MyClass();/创建创建MyClass的实例的实例Thread workth1 = new Thread(obj.method1);/创建一个工作线程创建一个工作线程workth1workth1.Start();/启动工作线程启动工作线程workt

51、h1Thread workth2 = new Thread(obj.method1);/创建一个工作线程创建一个工作线程workth2workth1.Start(10);/启动工作线程启动工作线程workth2,其中,其中10为实参为实参delegate void deletype1();/声明委托类型声明委托类型deletype1delegate void deletype2(object obj);/声明委托类型声明委托类型deletype2deletype1 mydele1;/定义委托变量定义委托变量mydele1deletype2 mydele2;/定义委托变量定义委托变量mydele

52、2MyClass a = new MyClass();/创建创建MyClass类的实例类的实例mydele1 = new deletype1(a.method1);mydele2 = new deletype2(a.method2);Thread workth1 = new Thread(new ThreadStart(mydele1);/创建一个工作线程创建一个工作线程workth1workth1.Start();/启动工作线程启动工作线程workth1Thread workth2 = new Thread(new ParameterizedThreadStart(mydele2); /创建

53、一个工作线程创建一个工作线程workth2workth2.Start(10);/启动工作线程启动工作线程workth2,其中,其中10为实参为实参采用委托方式创建和启动工作线程的过程如下:采用委托方式创建和启动工作线程的过程如下:3. 暂停线程暂停线程一旦线程已启动,就可以调用其方法来更改它的状态。一旦线程已启动,就可以调用其方法来更改它的状态。例如,例如,通过调用通过调用Thread.Sleep()可以使线程暂停一段时间可以使线程暂停一段时间(以毫秒为单位)。其使用语法格式如下:(以毫秒为单位)。其使用语法格式如下:Thread.Sleep(n);其中其中n为挂起的毫秒数,即线程保持锁定状态

54、的毫秒数。为挂起的毫秒数,即线程保持锁定状态的毫秒数。如果使用参数如果使用参数Infinite调用调用Sleep,则会导致线程休眠,则会导致线程休眠,直至调用直至调用Interrupt的另一个线程将其唤醒为止。的另一个线程将其唤醒为止。 Thread.Sleep(Timeout.Infinite);4. 中断线程中断线程Interrupt()Interrupt()方法会将目标线程从其可能处于的任何等方法会将目标线程从其可能处于的任何等待状态中唤醒,并导致引发待状态中唤醒,并导致引发ThreadInterruptedException异异常。常。通过对被阻止的线程调用通过对被阻止的线程调用Int

55、errupt()方法可以中断正方法可以中断正在等待的线程,从而使该线程脱离造成阻止的调用。在等待的线程,从而使该线程脱离造成阻止的调用。 线程应该捕获线程应该捕获ThreadInterruptedException异常并执行异常并执行任何适当的操作以继续运行。如果线程忽略该异常,则运任何适当的操作以继续运行。如果线程忽略该异常,则运行库将捕获该异常并停止该线程。行库将捕获该异常并停止该线程。5. 销毁线程销毁线程Abort()Abort()方法用于永久地停止托管线程。调用方法用于永久地停止托管线程。调用Abort时,时,公共语言运行库在目标线程中引发公共语言运行库在目标线程中引发ThreadA

56、bortException,目标线程可捕捉此异常。目标线程可捕捉此异常。Abort()方法不直接导致线程中止,因为目标线程可捕捉方法不直接导致线程中止,因为目标线程可捕捉ThreadAbortException并在并在finally块中执行任意数量的代码。块中执行任意数量的代码。 如果需要等待线程结束,可调用如果需要等待线程结束,可调用Join()方法。方法。Thread.Join()是一种模块化调用,它在线程实际停止执行之是一种模块化调用,它在线程实际停止执行之前,或可选超时间隔结束之前不会返回。等待对前,或可选超时间隔结束之前不会返回。等待对Join()方法方法的调用的线程可由其他线程调用

57、的调用的线程可由其他线程调用Interrupt()来中断。来中断。注意:一旦线程被中止,它将无法重新启动。如果线注意:一旦线程被中止,它将无法重新启动。如果线程已经在中止,则不能通过程已经在中止,则不能通过Start()来启动线程。来启动线程。线程状态关系图线程状态关系图 WaitSleepJoin:线程因为调用了:线程因为调用了Wait(),Sleep()或或Join()等方法处于封锁状态等方法处于封锁状态 Stopped:线程已经被停止:线程已经被停止 Running:线程正:线程正在正常运行在正常运行 AbortRequested:线:线程的程的Thread.Abort()方方法已被调用

58、,但是线法已被调用,但是线程还未停止程还未停止 Aborted:线程已停止:线程已停止 InterruptSleep,Joinusing System; using System.Threading;class ThreadTest static void Main() Thread t = new Thread (WriteY); t.Start(); / Run WriteY on the new thread while (true) Console.Write (x); / Write x forever static void WriteY() while (true) Consol

59、e.Write (y); / Write y forever 主线程创建了一个新线程主线程创建了一个新线程“t”,它运行了一个重复打,它运行了一个重复打印字母印字母y的方法,同时主线程重复打印字母的方法,同时主线程重复打印字母“x”。CLR分分配每个线程到它自己的内存堆栈上,来保证局部变量的分配每个线程到它自己的内存堆栈上,来保证局部变量的分离运行。离运行。 【例【例13.4】 分析以下程序的执行结果。分析以下程序的执行结果。using System;using System.Threading;/新增引用新增引用namespace Proj13_4public class Apublic v

60、oid fun()/定义类定义类A的方法的方法while (true) Console.WriteLine(工作线程工作线程:正在执行正在执行A.fun方法方法.); ;public class Programpublic static void Main() Console.WriteLine(主线程启动主线程启动.);A a = new A();/创建创建A类的实例类的实例 Thread workth = new Thread(new ThreadStart(a.fun); /创建一个线程,使之执行创建一个线程,使之执行A类的类的fun()方法方法 Console.WriteLine(工作

温馨提示

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

评论

0/150

提交评论