C#从异步调用中获取结果

时间:2010-04-13 15:26:22

标签: c# asynchronous

我有一个我正在使用的API,它的文档有限。有人告诉我,它执行的一些方法是异步调用的。

如何获得这些异步调用的结果。请注意,我没有做任何特殊的事情来调用它们,API处理异步部分。但我似乎无法从这些调用中得到“回复” - 我假设那是因为他们在另一个线程中。

更新 - 我在下面提供了一些代码。 API使用事件过程进行回调,但它似乎永远不会触发。

public partial class Window1 : Window
{
    ClientAppServer newServer= new ClientAppServer();

    public Window1()
    {
        InitializeComponent();
        newServer.ReceiveRequest += ReadServerReply;
    }


    private void ReadServerReply(RemoteRequest rr)
    {

        MessageBox.Show("reading server reply");
        if ((rr.TransferObject) is Gateways)
        {
            MessageBox.Show("you have gateways!");
        }
    }


    private void login()
    {
            newServer.RetrieveCollection(typeof(Gateways), true);

    }


    private void button1_Click(object sender, RoutedEventArgs e)
    {
        this.login();
    }

5 个答案:

答案 0 :(得分:6)

有几种方法可以在.NET中异步进行操作。由于您没有发布任何细节,我将概述更常见的模式:

<强> AsyncWaitHandle

通常,您会发现(特别是在.NET框架类中)以BeginEnd命名的方法对(即BeginReceiveEndReceive之类的方法)。

调用begin函数会返回一个AsyncWaitHandle对象,该对象可用于同步常规WaitHandle之类的线程(通过调用WaitOne或将其传递给静态WaitHandle.WaitAny或者WaitHandle.WaitAll函数),然后传递到相应的“end”函数以获取函数的返回值(或者,如果发生了一个函数,则抛出遇到的异常)。

如果使用简单的.NET工具异步调用方法(为函数创建委托并调用BeginInvokeEndInvoke),那么这就是您需要使用的方法。但是,大多数内置支持异步操作的API将为您处理实际的异步调用部分,为您留下正确命名的BeginXXXEndXXX函数,而不是强迫您自己创建委托

使用WaitHandle 的示例:

IAsyncResult result = object.BeginOperation(args);

result.AsyncWaitHandle.WaitOne(); 
// that will cause the current thread to block until
// the operation completes. Obviously this isn't
// exactly how you'd ordinarily use an async method
// (since you're essentially forcing it to be
// synchronous this way)

returnValue = object.EndOperation(result);

异步方法通常与事件耦合,如下所示。

<强>事件

有时,异步完成的方法调用将在事件完成时引发事件。这有时也与AsyncWaitHandle方法结合使用,以传递流程已完成的通知。例如,MSMQ库在队列对象上具有BeginReceiveEndReceieve函数,以及ReceieveCompleted事件。触发事件时,表示可以调用EndReceive,将调用返回的AsyncWaitHandle对象传递给BeginReceive。获取收到的实际消息。

无论哪种方式,您都会附加到事件中并像使用任何其他事件一样使用它。

使用AsyncWaitHandle和事件的示例:

(代码中的某处)

object.OperationComplete += object_OperationComplete;

(在别处)

IAsyncResult result = object.BeginOperation(args);

// at this point, you can either wait for the event
// to fire, or use the WaitHandle approach as shown
// in the previous example

...

void objectOperationComplete(object sender, AsyncOperationEventArgs e)
{
    returnValue = object.EndOperation(e.AsyncResult);
}

这些通常以各种方式工作......您可以自己保留从Begin操作返回的IAsyncResult,但是大多数库会将IAsyncResult对象作为特定属性传递给它们EventArgs上课。

查找返回值作为EventArgs类的属性也很常见。使用此值很好,如果Begin操作返回IAsyncResult,则调用相应的End函数总是一个好主意,即使您需要的数据在{{1 }}。 End函数通常也是捕获异常的方式。

<强>回调

回调(在.NET中)是提供给异步函数的委托。回调不仅仅用于异步函数,但在这种情况下,它们通常是一个委托,它在调用它完成时将调用的函数时提供。

回调类似于事件(因为它们都是基于委托的),尽管方法调用和提供的回调之间存在更多的一对一关联。

使用回调的示例

EventArgs

答案 1 :(得分:2)

通常,您会传入对该方法在完成时“回调”的函数的引用。有关此行为的一个很好的示例,请查看BackgroundWorker及其RunWorkCompleted事件。这被设置为属性而不是作为参数传递,但同样的想法适用。

如果你有一些源代码,或者至少是你正在使用的API的名称,我们可能会更具体。

以下是将回调方法作为参数传递的基本示例:

public SearchForm : Form
{
    public void StartSearch(string searchtext)
    {
        searcher.SearchAsync(searchtext, SearchCompleted);
    }

    public void SearchCompleted(IList<SearchResult> results)
    {
        // Called by the async searcher component, possibly on another thread

        // Consider marshalling to the UI thread here if you plan to update the UI like this:
        if (InvokeRequired) 
        {
            Invoke(new Action<IList<SearchResult>>(SearchCompleted), results);
            return;
        }

        foreach (var result in Results)
        {
            AddToList(result);
        }
    }
}

答案 2 :(得分:1)

有几种用于传递异步结果的习语。根据您的问题,我最好的猜测是您正在处理接受完成时调用的代理的方法(“回调”)。

您必须定义一个与委托类型匹配的方法,并将其传递给异步方法。完成后,它会调用您的委托,通常通过一个或多个委托的参数传递结果。

例如,如果您有这种异步方法:

public class Foo {
    public static void DoSomethingAsynchronous(SimpleCallback simpleCallback) {

        // First this method does something asynchronous

        // Then it calls the provided delegate, passing the operation's results
        simpleCallback(true);
    }
}

// The result parameter can be much richer - it's your primary mechanism for
// passing results back to the caller.
public delegate SimpleCallback(bool result);

你会这样称呼:

public static void Main(string[] args) {
    Foo.DoSomethingAsynchronous(WriteResultToConsole);
}

// Here's your SimpleCallback
public static WriteResultToConsole(bool result) {
    Console.WriteLine(result? "Success!" : "Failed!");
}

答案 3 :(得分:0)

通过将指针传递给回调函数,可以从异步调用中获得结果。请告诉我们您要拨打的API,有人可能会为您提供一些示例代码。

答案 4 :(得分:0)

您需要使用BeginInvoke和EndInvoke方法。

本文介绍如何异步调用方法:

http://support.microsoft.com/kb/315582