2.1C#委托机制2.2C#多线程2.3C#方法回调①MethodA直接调用MethodB的方式:privatevoidbutton1_Click(objectsender,EventArgse){MethodA();}privatevoidMethodA(){MessageBox.Show(MethodA);MethodB(abcd);}privatevoidMethodB(stringb){MessageBox.Show(b,MethodB);}2.1.1初识委托委托是间接调用方法的一种机制。MethodA可以直接调用MethodB,也可以使用委托间接调用MethodB。②MethodA使用委托间接调用MethodB的方式:privatedelegatevoidMyDelegate(stringstr);//1.定义委托。委托的本质是类,类的定义不能再方法体中进行MyDelegatemydel;//2.声明委托privatevoidbutton1_Click(objectsender,EventArgse){mydel=newMyDelegate(MethodB);//3.实例化委托对象将MethodB作为参数与委托绑定MethodA(mydel);//4.将委托作为MethodA的参数}privatevoidMethodA(MyDelegatedele){MessageBox.Show(MethodA);dele(abcd);//5.使用委托}privatevoidMethodB(stringb){MessageBox.Show(b,MethodB);}MethodB的形参和返回值类型都与委托一致MethodA不是直接调用MethodB,而是通过委托间接调用MethodBMethodA的形参是委托类型使用委托的步骤:①使用关键字delegate定义委托:delegate返回值MyDelegate(形参表);②声明委托对象d:MyDelegated;③实例化委托对象d:d=newMyDelegate(MethodB);④将d用作方法A的参数:MethodA(d);⑤最后在方法A的实现代码中使用委托:privatevoidMethodA(MyDelegatedel){…//使用委托del(实参表);…}方法B的返回值、形参表与委托的返回值、形参表保持一致:private返回值MethodB(形参表){……}这里先给出一个“文字抄写员”小程序,界面如下:textBox1和textBox2分别用来抄写textBox3中的文字【例2-1】ProcessMethodCall定义两个方法writeTextBox1()和writeTextBox2()分别用于向文本区①和文本区②中写入文字,然后在【提交】按钮的事件过程中直接调用这两个方法,实现程序书写的功能。在书写文本时,每写入一个字,都使用while语句间歇延时1秒钟以便更加形象地展示程序的运行过程。privatevoidwriteTextBox1()//写文本区①的方法{stringstrdata=textBox3.Text;for(inti=0;istrdata.Length;i++){textBox1.AppendText(strdata[i]+);DateTimenow=DateTime.Now;while(now.AddSeconds(1)DateTime.Now){}}}privatevoidwriteTextBox2()//写文本区②的方法{stringstrdata=textBox3.Text;for(inti=0;istrdata.Length;i++){textBox2.AppendText(strdata[i]+);DateTimenow=DateTime.Now;while(now.AddSeconds(1)DateTime.Now){}}}只有一行代码不同【例2-2】ProcessDelegate对比使用传统方法调用的程序版本,应用委托后只要定义一段方法代码,就可以实现与原来程序一样的功能。使用委托可以减少重复代码。privatevoidWriTxt(WriteTextBoxwMethod){stringstrdata=textBox3.Text;for(inti=0;istrdata.Length;i++){wMethod(strdata[i]);//使用委托//间歇延时DateTimenow=DateTime.Now;while(now.AddSeconds(1)DateTime.Now){}}}定义、声明委托:privatedelegatevoidWriteTextBox(charch);privateWriteTextBoxwriteTextBox;WriTxt(WriteTextBoxwMethod)执行公共代码非公共代码使用委托执行:wMethod(ch);WriteTextBox1(charch)textBox1.AppendText(ch+);WriteTextBox2(charch)textBox2.AppendText(ch+);button1_ClickwriteTextBox=newWriteTextBox(WriteTextBox1);WriTxt(writeTextBox);writeTextBox=newWriteTextBox(WriteTextBox2);WriTxt(writeTextBox);例2-2委托的使用委托是一个特殊的类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用if-else或Switch语句,同时也使得程序具有更好的扩展性。2.2.1线程概述一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程。线程是操作系统分配处理器时间的基本单元,在进程中可以有多个线程同时执行代码。线程上下文包括为使线程在其宿主进程地址空间中无缝地继续执行所需的所有信息,包括线程的CPU寄存器组和堆栈。每个应用程序域都是用单个线程启动的,但该应用程序域中的代码可以创建附加应用程序域和附加线程。必须认识到线程本身可能存在影响系统性能的不利方面,才能正确使用线程。不利方面主要有:(1)线程需要占用内存,线程越多占用内存也越多。(2)多线程需要协调和管理,需要占用CPU时间来跟踪线程。(3)线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题。(4)线程太多会导致控制太复杂,最终可能造成很多Bug。例如在VS2008中新建一个Windows窗体应用程序,打开解决方案资源管理器树形目录下的“Program.cs”文件,其代码如下。staticclassProgram{///summary///应用程序的主入口点。////summary[STAThread]staticvoidMain(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(newForm1());}}通过实例化一个Thread对象就可以创建一个线程。创建新的Thread对象时,将创建新的托管线程。Thread类接收一个ThreadStart委托或ParameterizedThreadStart委托的构造函数,该委托包装了调用Start方法时由新线程调用的方法。Threadthread=newThread(newThreadStart(method));//创建线程thread.Start();//启动线程上述代码实例化了一个Thread对象,并指明将要调用的方法method(),然后启动线程。ThreadStart委托中作为参数的方法不需要参数,并且没有返回值。ParameterizedThreadStart委托一个对象为参数,利用这个参数可以很方便地向线程传递参数,示例代码如下。Threadthread=newThread(newParameterizedThreadStart(method));//创建线程thread.Start(3);//启动线程并传参数3电脑软件早已是图形用户界面(GUI)时代,一个软件的好坏很大程度上依赖于最终用户的主观使用体验,而影响用户体验的一个至关重要的因素就是界面的交互性和响应速度。【例2-3】SingleThread本例与例2-1不同之处在于:将原来【提交】按钮的过程代码移植到方法DoTsk()中,而在单击【提交】按钮时执行一段启动线程的代码,如下。ThreadStartdoTask=newThreadStart(DoTsk);ThreadtskThread=newThread(doTask);tskThread.Start();另外,线程类位于System.Threading命名空间中,需要引用该命名空间。privatedelegatevoidWriteTextBox(charch);privateWriteTextBoxwriteTextBox;DoTskif(checkBox1.Checked){WriteTextBox1();}if(checkBox2.Checked){WriteTextBox2();}WriteTextBox1()书写到文本区1WriteTextBox2()书写到文本区2button1_ClickThreadtskThread=newThread(newThreadStart(DoTsk));tskThread.Start();例2-3单线程+传统调用方式将程序代码放到一个单独的线程中执行有什么好处?比较例2-3与例2-1运行效果发现:运行例2-1时,点击界面没有反应;而运行例2-3时,点击界面能够做出反应。语句CheckForIllegalCrossThreadCalls=false;表示允许跨线程访问控件。注释该语句,运行时提示:线程间操作无效:从不是创建控件“groupBox2”的线程访问它。例2-3的单线程程序是用传统的方法调用方式实现的,也可以改用委托方式实现。例2-4ThreadDelegate用委托方式实现单线程程序。点击提交按钮则启动线程,在该线程中利用委托实现文字抄写。privatedelegatevoidWriteTextBox(charch);privateWriteTextBoxwriteTextBox;WriTxt(WriteTextBoxwMethod)执行公共代码非公共代码使用委托执行:wMethod(ch);WriteTextBox1(charch)textBox1.AppendText(ch+);WriteTextBox2(charch)textBox2.AppendText(ch+);例2-4单线程+委托DoTskif(checkBox1.Checked){writeTextBox=newWriteTextBox(WriteTextBox1);WriTxt(writeTextBox);}if(checkBox2.Checked){writeTextBox=newWriteTextBox(WriteTextBox2);WriTxt(writeTextBox);}button1_ClickThreadtskThread=newThread(newThreadStart(DoTsk));tskThread.Start();下面实现一个“文字抄写员”程序的多线程版本。【例2-5】MultiThread多线程+委托的使用只要同时启动这两个线程,就可以向两个文本区同时写入文本。privatedelegatevoidWriteTextBox(charch);privateWriteTextBoxwriteTextBox;WriTxt(WriteTextBoxwMethod)执行公共代码非公共代码使