委托,begininvoke,endinvoke

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 线程实验2
{
    class Program
    {
        public delegate object myDelegate(object o);
        public static myDelegate myDel;
        static void Main(string[] args)
        {
           myDel=new myDelegate(cal);
           myDel.BeginInvoke(5,new AsyncCallback(callback),myDel);//5是委托方法需要的参数,mydel是传给回调函数的状态
           Console.ReadLine();
        }
        public static object cal(object o)
        {
          (o)*5;      //这里值得注意,将object先拆箱,在装箱。具体的定义请参考msdn
        }
        public static void callback(IAsyncResult iar)
        {
            myDel =(myDelegate)iar.AsyncState;   //获得主函数传过来的状态,要用到强制类型转换
            object t = myDel.EndInvoke(iar);     //EndInvoke方法的返回值就是被调用方法的返回值,即cal的返回值
            Console.WriteLine(t.ToString());
        }
  
    }

}

/*大家可以单步一下,看程序的执行顺序,反正我是大开眼界
*/

/**********************************************************************************************************************************/

多播委托(MulticastDelegate)提供了一种类似于流水线式的钩子机制只要加载到这条流水线上的委托,都会被顺序执行。因为所有的委托都继承自MulticastDelegate,因此所有的委托都具备多播特性。最简单的理解:一个委托,但同时可以执行多个方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托试验3
{
    class Program
    {
        public delegate void MyDelgegate(string str);
        public static MyDelgegate Mydel1 = new MyDelgegate(callback1); 
        public static MyDelgegate Mydel2 = new MyDelgegate(callback2);
        public static MyDelgegate Mydel3;
        static void Main(string[] args)
        {
            Mydel3 += Mydel1;                               
            Mydel3 += Mydel2;                                                //将callback1和callback2方法都加到mydel3中去。
            Mydel3("Hello,FirstCallBack!");
            Mydel3 -= Mydel1;                                               // 将callback1从委托mydel3中去除
            Mydel3("Hello,SecondCallBack!");
            //ydel2("Hello,SecondCallBack!");
            Console.ReadLine();
        }
        public static void callback1(string str)
        {
            Console.WriteLine("这是第一个调用!"+str);
        }
        public static void callback2(string str)
        {
            Console.WriteLine("这是第二个调用!" + str);
        }
    }
}

调试结果为:

 

<think>好的,我现在需要帮助用户理解C#中的异步调用,特别是使用委托BeginInvokeEndInvoke方法。首先,用户之前询问了关于事件和委托的代码解释,所以可能已经对委托有一定的了解。接下来,用户现在想了解异步调用,尤其是BeginInvokeEndInvoke的使用方法。 首先,我需要确认用户的基础知识。用户可能已经知道委托是什么,但可能需要复习一下,因为异步调用是基于委托的。然后,我需要解释BeginInvokeEndInvoke的作用,以及它们在异步编程中的角色。 接下来,我应该考虑用户可能的疑问点。比如,BeginInvokeEndInvoke是如何工作的?为什么使用它们?与同步调用相比有什么优势?还有,这些方法在现代C#中的状态,因为微软可能推荐使用更现代的异步模式,比如async/await,而不是旧的APM模式。 然后,我需要组织信息,确保结构清晰。可能分成几个部分:异步调用的概念、BeginInvoke/EndInvoke的使用步骤、代码示例、执行流程、优缺点分析以及现代替代方案。这样用户可以逐步理解。 需要注意用户可能对线程池、IAsyncResult接口等概念不熟悉,需要适当解释,但不要过于深入,避免信息过载。同时,要提醒用户这些方法现在可能不推荐使用,避免他们在新项目中错误地采用过时的技术。 另外,用户之前的回复中提到了事件处理,可能需要将异步调用与事件机制联系起来,说明它们如何协同工作。不过,当前的回答可能需要专注于委托的异步调用本身,而不是事件。 还要考虑代码示例的正确性。确保示例简单明了,能够展示BeginInvokeEndInvoke的基本用法,并解释每个步骤的作用。同时,指出潜在的问题,比如未调用EndInvoke导致的资源泄漏,以及跨线程访问的问题。 最后,总结优缺点,并引导用户了解现代替代方案,比如Task和async/await,这样他们知道现在更推荐的方法是什么,以及为什么旧的方法可能不再适用。 现在,我需要确保整个解释逻辑连贯,覆盖所有关键点,并且用用户容易理解的语言表达。避免使用过多术语,或者在必要时解释术语。同时,保持回答的结构化,使用标题和分点,方便用户阅读和理解。</think>以下是关于C#委托异步调用的分步解析: $$异步调用模型图$$ ``` 主线程 │ ├── BeginInvoke() → 触发异步操作 │ │ │ └── 线程池线程执行委托方法 │ └── 继续执行其他代码... │ └── EndInvoke() ← 获取结果(阻塞等待) ``` ### 一、核心机制 1. **异步编程模型(APM)** - 基于`IAsyncResult`接口实现 - 使用`BeginInvoke`启动异步操作 - 通过`EndInvoke`获取结果 2. **线程池管理** ```csharp BeginInvoke() → 自动分配线程池线程 ``` - 默认使用.NET线程池(无需手动管理线程) ### 二、标准使用流程 1. **定义委托** ```csharp public delegate int CalculateHandler(int x, int y); ``` 2. **异步调用** ```csharp CalculateHandler handler = (a, b) => { Thread.Sleep(2000); // 模拟耗时操作 return a + b; }; // 启动异步调用 IAsyncResult result = handler.BeginInvoke(3, 4, null, null); // 主线程继续执行其他任务 Console.WriteLine("主线程继续工作..."); // 获取结果(阻塞直到完成) int sum = handler.EndInvoke(result); Console.WriteLine($"结果:{sum}"); ``` ### 三、回调函数用法 ```csharp handler.BeginInvoke(3, 4, ar => { int result = handler.EndInvoke(ar); Console.WriteLine($"回调结果:{result}"); }, null); ``` ### 四、执行时序分析 ``` 时间轴 主线程 线程池线程 │ ├── BeginInvoke() → 请求异步操作 │ │ │ ├── 2秒后完成计算 │ ├── 输出"主线程继续工作..." │ ├── EndInvoke() ← 阻塞等待 │ │ │ └── 返回结果7 │ └── 输出"结果:7" ``` ### 五、关键注意事项 1. **必须调用EndInvoke** - 即使不需要返回值,也必须调用以避免资源泄漏 - 最佳实践:使用`try-catch`包裹EndInvoke 2. **跨线程访问** ```csharp // 错误示例(跨线程更新UI) handler.BeginInvoke(3, 4, ar => { this.Label.Text = handler.EndInvoke(ar).ToString(); // 可能引发异常 }, null); // 正确方式(使用Control.Invoke) handler.BeginInvoke(3, 4, ar => { this.Invoke(() => { this.Label.Text = handler.EndInvoke(ar).ToString(); }); }, null); ``` ### 六、现代替代方案 1. **Task并行库(推荐)** ```csharp Task.Run(() => { return 3 + 4; }).ContinueWith(t => { Console.WriteLine($"结果:{t.Result}"); }); ``` 2. **async/await模式** ```csharp public async Task CalculateAsync() { int result = await Task.Run(() => 3 + 4); Console.WriteLine($"结果:{result}"); } ``` ### 七、性能对比表 | 特性 | BeginInvoke | Task | |-------------------|-------------|------------| | 线程池利用 | ✓ | ✓ | | 异常传播 | 需手动处理 | 自动捕获 | | 取消支持 | × | ✓ | | 进度报告 | × | ✓ | | .NET Core 支持 | × | ✓ | 建议:在新代码中优先使用`Task`或`async/await`,这些旧式异步模式主要用于维护遗留代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值