C # получение результатов от асинхронного вызова - PullRequest
2 голосов
/ 13 апреля 2010

У меня есть 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 ]

6 голосов
/ 13 апреля 2010

Существует несколько способов, с помощью которых операции могут выполняться асинхронно в .NET. Поскольку вы не опубликовали никаких подробностей, я дам обзор наиболее распространенных шаблонов:

AsyncWaitHandle

Часто вы найдете (особенно в классах .NET Framework) пары методов с именами Begin и End (т.е. что-то вроде BeginReceive и EndReceive).

Вызов функции begin возвращает объект AsyncWaitHandle, который можно использовать для синхронизации потоков, как обычный WaitHandle (путем вызова WaitOne или передачи его в статические функции WaitHandle.WaitAny или WaitHandle.WaitAll), затем передается в соответствующую функцию "end", чтобы получить возвращаемое значение функции (или, если оно произошло, сгенерировать возникшее исключение).

Если вы используете простое средство .NET для асинхронного вызова метода (создания делегата для функции и вызова BeginInvoke и EndInvoke), то вам следует использовать этот подход. Однако большинство API, которые имеют встроенную поддержку асинхронных операций, будут обрабатывать фактическую асинхронную вызывающую часть для вас, оставляя вас с правильно названными функциями BeginXXX и EndXXX, вместо того, чтобы заставлять вас создавать делегата самостоятельно.

Образец с использованием 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 имеют функцию BeginReceive и EndReceieve для объекта очереди, а также событие ReceieveCompleted. Когда событие вызывается, это означает, что затем может быть вызван EndReceive, передав объект AsyncWaitHandle, возвращенный вызовом BeginReceive. чтобы получить фактическое сообщение, которое было получено.

В любом случае, вы присоединяетесь к событию и используете его, как и любое другое событие.

Пример использования AsyncWaitHandle и событий :

(где-то в коде)

object.OperationComplete += object_OperationComplete;

(в другом месте) * 1 057 *

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);
}

Как правило, они работают различными способами ... вы можете самостоятельно удерживать IAsyncResult, возвращаемый операцией Begin, но большинство библиотек передают этот объект IAsyncResult как свойство в свой конкретный класс EventArgs .

Также обычно можно найти возвращаемое значение, присутствующее в качестве свойства в классе EventArgs. Хотя использовать это значение можно, , если операция Begin вернула IAsyncResult, всегда полезно вызывать соответствующую функцию End , даже если необходимые данные находятся в EventArgs. Функция End также обычно используется для обнаружения исключений.

Callbacks

Обратный вызов (в .NET) - это делегат, который предоставляется асинхронной функции. Обратные вызовы используются не только в асинхронных функциях, но в этом контексте они, как правило, являются делегатами, которые вы предоставляете при вызове функции, которую она будет вызывать по завершении.

Обратные вызовы аналогичны событиям (в том смысле, что они оба основаны на делегатах), хотя между вызовами методов и предоставленными обратными вызовами существует большая взаимно-однозначная корреляция.

Пример использования обратного вызова :

object.BeginOperation(args, OperationComplete);

...

void OperationComplete(SomeObject results)
{
    ...
}
2 голосов
/ 13 апреля 2010

Как правило, вы передаете ссылку на функцию, которую метод "перезвонит", когда она будет завершена.Для отличного примера такого поведения посмотрите на 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);
        }
    }
}
1 голос
/ 13 апреля 2010

Есть несколько идиом для передачи асинхронных результатов. Исходя из вашего вопроса, я думаю, что вы имеете дело с методами, которые принимают делегатов, которые они вызывают по завершении («обратные вызовы»).

Вы должны определить метод, который соответствует типу делегата, и передать его асинхронному методу. Когда он заканчивается, он вызывает вашего делегата, обычно передавая результаты через один или несколько параметров делегата.

Например, если у вас есть этот асинхронный метод:

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!");
}
0 голосов
/ 13 апреля 2010

Вам необходимо использовать методы BeginInvoke и EndInvoke.

В этой статье показано, как вызвать метод асинхронно:

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

0 голосов
/ 13 апреля 2010

Вы получаете свой результат от асинхронных вызовов, передавая указатель на функцию обратного вызова. Пожалуйста, дайте нам знать, какой API вы пытаетесь вызвать, и кто-то, вероятно, предоставит вам пример кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...