C# 异步调用中使用回调方法

        在上篇文章提到了进行异步调用的时候,我们可以手动指定超时时间和阻塞时间,然后再调用委托的EndInvoke()方法得到我们要的结果。然而,如果我们想在进行异步调用的时候进行很好的管理得话,那使用完成回调方法将是一个不错的选择。

        一:回调方法的签名和工作机制
        1.回调方法必须要符合以下签名:
        <修饰符>void <方法名>(IAsynResult asynResult);回调的方法的名称的统一规范是在名称前面加On ,如:OnAsynCallBack();(注:命名事件和委托等类型时候同样有类似的惯例),
        2.工作机制:
        .Net使用从线程池中得到的线程来执行通过BeginInvoke()分配的方法,当异步方法执行完成时,工作线程调用回调方法而不只直接回到线程池中,要实现回调方法,我们必须在使用beginInvoke()方法的时候指定一个参数为IAsynResult类型的方法,因为在AsynResult是一个.Net中已经定义好的委托,我们要使用回调方法的话,就必须符合他的要求:他的定义如下,public delegate void AsynCallBack(IAsynResult asynResult);

        示例:

        
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Diagnostics;

namespace Asyn
{
    
public delegate int BinaryOperation(int argument1,int argument2);

    
class Program
    
{
        
static void Main(string[] args)
        
{
            CalCulatorClent.AsynAdd();
        }

    }


    
public class Calculator
    
{
        
public int Add(int argument1, int argument2)
        
{
            
return argument1 + argument2;
        }


        
public int Sub(int argument1, int argument2)
        
{
            
return argument1 - argument2;
        }

    
    }


    
public class CalCulatorClent
    
{
        
public static void AsynAdd()
        
{

            Calculator calculator 
= new Calculator();
            BinaryOperation oppDel 
= calculator.Add;
            oppDel.BeginInvoke(
23, OnMethodCompletion, null);

        }

        
private static void OnMethodCompletion(IAsyncResult asynResult)
        
{
            
int result = 0;

            AsyncResult resultObj
=(AsyncResult)asynResult;
            System.Diagnostics.Debug.Assert(resultObj.EndInvokeCalled
==false);//如果没调用,则输出

            BinaryOperation oppDel 
= (BinaryOperation)resultObj.AsyncDelegate;//获取原来的委托
            result = oppDel.EndInvoke(asynResult);
            Console.WriteLine(
"Operation returned "+result.ToString());
            Console.Read();
        }

    }


}

            
注:上面的示例有一个要值得注意,就是获取原始委托的方法,获取原始委托用的是System.Runtime.Remoting.Messaging;
名字空间下的AsynResult,它继承自IAsynResult,通过它的AsyncDelegate属性,我们就得到了对应BeginInvoke()方法的委托,同时还可以利用它的属性EndInvokeCalled来确定EndInvoke()是否被调用。

二:回调方法与线程安全
   因为回调方法是在线程池中的一个线程中运行的,所以关于线程安全方面也要考虑。特别是对于一些共享资源如数据库连接对象等就要考虑到并发带来的问题,我们可以加同步锁(用lock关键字)来访问这些资源。

三:传递状态信息

BeginInvoke()的最后一个参数,object asyncState,作为.NET中的作为泛用容器被提供的状态对象。处理方法完成的部分可以访问类似于IAsyncResult中AsyncState属性的容器对象。虽然也可以在其他.NET异步调用编程模型(阻塞,等待或轮询)中使用状态对象,但与完成方法一起使用时最有用处。原因很简单:在其他编程模型中,不仅必须管理IAsyncResult对象,而且还要管理一个额外的增加管理责任的容器对象。当通过完成回调使用容器对象时,仅需要给回调方法传入一个额外的参数,而且已通过.NET在方法签名中预订了。





posted @ 2007-09-18 14:06  寒蝉  阅读(3913)  评论(2编辑  收藏  举报