C#中异步回调函数用法实例

远山来客
远山来客
发布时间:2026-10-14 | 4人浏览过
原创

在C#异步编程中,利用委托的 BeginInvoke 配合 AsyncCallback 可实现非阻塞的任务执行与结果回传。本文将通过具体代码演示如何发起异步调用、检测状态以及通过回调函数安全获取返回值。

异步回调的实现原理

C#中的异步委托允许将耗时操作(如I/O密集型任务或长时间计算)放入线程池执行,防止主线程(通常是UI线程或请求处理线程)被阻塞。通过 BeginInvoke 方法,我们可以传入回调函数,当异步任务结束时,该回调将在后台线程自动执行,从而通知调用者任务已完成。

完整操作代码示例

以下代码展示了一个完整的异步委托使用场景:定义一个异步委托,设置回调函数,并在等待期间模拟主线程进行其他操作。

static void Main(string[] args)
{
    // 1. 定义代理委托,指向同步方法 ShowMessage
    Func<string,string> showMessage = ShowMessage;
    
    // 2. 启动异步操作
    // 参数说明:
    // - "测试异步委托":传递给 ShowMessage 的参数
    // - new AsyncCallback(Completed):异步完成时执行的回调方法
    // - null:用户自定义对象,用于向回调传递额外状态(此处未使用)
    IAsyncResult result = showMessage.BeginInvoke("测试异步委托",new AsyncCallback(Completed),null);
    
    // 3. 主线程非阻塞等待
    while(!result.IsCompleted)
    {
        Console.WriteLine("主线程可以进行其它的操作!");
        Thread.Sleep(100); // 建议加入短暂休眠以减少CPU占用
    }
    
    Console.ReadLine();
}

// 被调用的同步方法(将在后台线程执行)
static string ShowMessage(string x)
{
    string current = string.Format("当前线程id为{0}",Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(3000); // 模拟耗时操作
    return string.Format("{0},输入为{1}", current, x);
}

// 异步完成后的回调方法
static void Completed(IAsyncResult result)
{
    Console.WriteLine("异步完成!");
    
    // 4. 在回调中获取返回值
    // 注意:必须在回调中或主线程中调用 EndInvoke 以释放资源并获取结果
    AsyncResult _result = (AsyncResult) result;
    Func<string, string> showMessage = (Func<string, string>) _result.AsyncDelegate;
    
    // 结束异步操作并输出结果
    Console.WriteLine(showMessage.EndInvoke(_result));
}

关键步骤解析

第1步:定义委托与方法

首先定义一个符合签名的委托(如 Func<string, string>),并将具体的业务逻辑封装在同步方法(如 ShowMessage)中。即使业务逻辑是异步的,使用委托模式也能统一入口。

第2步:调用 BeginInvoke

使用委托变量的 BeginInvoke 方法启动异步执行。第二个参数传入 AsyncCallback 委托,指向完成后需要执行的方法。此时方法立即返回 IAsyncResult 对象,主线程控制权交还,可以继续执行后续逻辑。

第3步:监测状态与等待(可选)

示例中通过轮询 result.IsCompleted 来确保在主线程不退出前看到结果。在实际应用中,如果使用回调机制,通常不需要在主线程显式等待,因为 EndInvoke 应在回调内部或通过其他方式调用。若需同步等待,可使用 result.AsyncWaitHandle.WaitOne()。

第4步:在回调中获取结果

这是易错点。Completed 方法本身没有返回值,因此无法直接返回 ShowMessage 的结果。必须通过 IAsyncResult 获取原始的委托对象(_result.AsyncDelegate),然后强制转换回原来的委托类型,再次调用 EndInvoke。 EndInvoke 的作用是:

  • 阻塞直到异步操作真正结束(如果在 BeginInvoke 后立即调用);
  • 捕获异步操作中抛出的异常;
  • 获取方法的返回值。

注意事项与排错

  • 线程上下文切换:回调函数 Completed 运行在CLR线程池线程上,而非主线程。如果需要更新UI控件(如WinForms/WPF),必须使用 Control.Invoke 或 Dispatcher.Invoke 将操作封送回UI线程,否则可能抛出跨线程操作异常。
  • 内存泄漏:务必对每个 BeginInvoke 调用对应的 EndInvoke,无论成功还是失败。未调用 EndInvoke 会导致内存和资源泄漏。
  • 参数传递:如果需要在回调中传递复杂数据,可以通过 BeginInvoke 的第四个参数 state 传入一个包含所需信息的对象,并在回调中通过 (MyStateClass)result.AsyncState 获取。

以上就是C#中异步回调函数用法的详细内容,更多关于C#异步编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表