Llamar a métodos sincrónicos de forma asincrónicaCalling Synchronous Methods Asynchronously

.NET Framework permite llamar a cualquier método de forma asincrónica.The .NET Framework enables you to call any method asynchronously. Para ello, es necesario que defina un delegado con la misma firma que el método al que desea llamar. Common Language Runtime definirá automáticamente los métodos BeginInvoke y EndInvoke para este delegado, con las firmas adecuadas.To do this you define a delegate with the same signature as the method you want to call; the common language runtime automatically defines BeginInvoke and EndInvoke methods for this delegate, with the appropriate signatures.

Nota

Las llamadas de delegado asincrónicas, específicamente los métodos BeginInvoke y EndInvoke , no se admiten en .NET Compact Framework.Asynchronous delegate calls, specifically the BeginInvoke and EndInvoke methods, are not supported in the .NET Compact Framework.

El método BeginInvoke inicia la llamada asincrónica.The BeginInvoke method initiates the asynchronous call. Tiene los mismos parámetros que el método que desea ejecutar de forma asincrónica, más dos parámetros opcionales adicionales.It has the same parameters as the method that you want to execute asynchronously, plus two additional optional parameters. El primer parámetro es un delegado AsyncCallback que hace referencia a un método que se habrá de llamar cuando finalice la llamada asincrónica.The first parameter is an AsyncCallback delegate that references a method to be called when the asynchronous call completes. El segundo parámetro es un objeto definido por el usuario que pasa información al método de devolución de llamada.The second parameter is a user-defined object that passes information into the callback method. BeginInvoke vuelve inmediatamente y no espera que se complete la llamada asincrónica.BeginInvoke returns immediately and does not wait for the asynchronous call to complete. BeginInvoke devuelve IAsyncResult, que se puede usar para supervisar el progreso de la llamada asincrónica.BeginInvoke returns an IAsyncResult, which can be used to monitor the progress of the asynchronous call.

El método EndInvoke recupera los resultados de la llamada asincrónica.The EndInvoke method retrieves the results of the asynchronous call. Se puede llamar en cualquier momento después de ejecutar BeginInvoke.It can be called any time after BeginInvoke. Si la llamada asincrónica no ha completado, EndInvoke bloquea el subproceso que realiza la llamada hasta que se completa.If the asynchronous call has not completed, EndInvoke blocks the calling thread until it completes. Entre los parámetros de EndInvoke se incluyen los parámetros out y ref (<Out> ByRef y ByRef en Visual Basic) del método que desea ejecutar de forma asincrónica, además de la interfaz IAsyncResult devuelta por BeginInvoke.The parameters of EndInvoke include the out and ref parameters (<Out> ByRef and ByRef in Visual Basic) of the method that you want to execute asynchronously, plus the IAsyncResult returned by BeginInvoke.

Nota

La característica IntelliSense en Visual Studio muestra los parámetros de BeginInvoke y EndInvoke.The IntelliSense feature in Visual Studio displays the parameters of BeginInvoke and EndInvoke. Si no utiliza Visual Studio u otra herramienta similar, o si está utilizando C# con Visual Studio, consulte Modelo de programación asincrónica (APM), donde encontrará una descripción de los parámetros definidos para estos métodos.If you're not using Visual Studio or a similar tool, or if you're using C# with Visual Studio, see Asynchronous Programming Model (APM) for a description of the parameters defined for these methods.

En los ejemplos de código de este tema se muestran cuatro de las formas más comunes de utilizar los métodos BeginInvoke y EndInvoke para realizar llamadas asincrónicas.The code examples in this topic demonstrate four common ways to use BeginInvoke and EndInvoke to make asynchronous calls. Después de llamar a BeginInvoke , puede hacer lo siguiente:After calling BeginInvoke you can do the following:

  • Realizar algunas operaciones y, a continuación, llamar al método EndInvoke para que mantenga un bloqueo hasta que se complete la llamada.Do some work and then call EndInvoke to block until the call completes.

  • Obtener un objeto WaitHandle mediante la propiedad IAsyncResult.AsyncWaitHandle , utilizar su método WaitOne para bloquear la ejecución hasta que se señalice WaitHandle y, a continuación, llamar al método EndInvoke.Obtain a WaitHandle using the IAsyncResult.AsyncWaitHandle property, use its WaitOne method to block execution until the WaitHandle is signaled, and then call EndInvoke.

  • Sondear el resultado IAsyncResult devuelto por BeginInvoke para determinar cuándo se completa la llamada asincrónica y, a continuación, llamar al método EndInvoke.Poll the IAsyncResult returned by BeginInvoke to determine when the asynchronous call has completed, and then call EndInvoke.

  • Pasar un delegado de un método de devolución de llamada a BeginInvoke.Pass a delegate for a callback method to BeginInvoke. El método se ejecuta en un subproceso ThreadPool una vez finalizada la llamada asincrónica.The method is executed on a ThreadPool thread when the asynchronous call completes. El método de devolución de llamada llama a EndInvoke.The callback method calls EndInvoke.

Importante

Con independencia de la técnica que utilice, llame siempre a EndInvoke para completar la llamada asincrónica.No matter which technique you use, always call EndInvoke to complete your asynchronous call.

Definir el método Test y el delegado asincrónicoDefining the Test Method and Asynchronous Delegate

En los ejemplos de código siguientes se muestran distintas maneras de llamar al mismo método de ejecución prolongada, TestMethod, de forma asincrónica.The code examples that follow demonstrate various ways of calling the same long-running method, TestMethod, asynchronously. El método TestMethod muestra un mensaje en la consola para indicar que ha comenzado el procesamiento, espera unos segundos y, a continuación, finaliza.The TestMethod method displays a console message to show that it has begun processing, sleeps for a few seconds, and then ends. TestMethod tiene un parámetro out para mostrar la manera en que esos parámetros se agregan a las firmas de BeginInvoke y EndInvoke.TestMethod has an out parameter to demonstrate the way such parameters are added to the signatures of BeginInvoke and EndInvoke. Los parámetros ref se pueden controlar de manera similar.You can handle ref parameters similarly.

En el ejemplo de código siguiente se muestra la definición de TestMethod y el delegado denominado AsyncMethodCaller que se puede utilizar para llamar a TestMethod de forma asincrónica.The following code example shows the definition of TestMethod and the delegate named AsyncMethodCaller that can be used to call TestMethod asynchronously. Para compilar cualquiera de los ejemplos de código, debe incluir las definiciones del método TestMethod y el delegado AsyncMethodCaller .To compile the code examples, you must include the definitions for TestMethod and the AsyncMethodCaller delegate.

using namespace System;
using namespace System::Threading;
using namespace System::Runtime::InteropServices; 

namespace Examples {
namespace AdvancedProgramming {
namespace AsynchronousOperations
{
    public ref class AsyncDemo 
    {
    public:
        // The method to be executed asynchronously.
        String^ TestMethod(int callDuration, [OutAttribute] int% threadId) 
        {
            Console::WriteLine("Test method begins.");
            Thread::Sleep(callDuration);
            threadId = Thread::CurrentThread->ManagedThreadId;
            return String::Format("My call time was {0}.", callDuration);
        }
    };

    // The delegate must have the same signature as the method
    // it will call asynchronously.
    public delegate String^ AsyncMethodCaller(int callDuration, [OutAttribute] int% threadId);
}}}
using System;
using System.Threading; 

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncDemo 
    {
        // The method to be executed asynchronously.
        public string TestMethod(int callDuration, out int threadId) 
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
    }
    // The delegate must have the same signature as the method
    // it will call asynchronously.
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations
    Public Class AsyncDemo 
        ' The method to be executed asynchronously.
        Public Function TestMethod(ByVal callDuration As Integer, _
                <Out> ByRef threadId As Integer) As String
            Console.WriteLine("Test method begins.")
            Thread.Sleep(callDuration)
            threadId = Thread.CurrentThread.ManagedThreadId()
            return String.Format("My call time was {0}.", callDuration.ToString())
        End Function
    End Class

    ' The delegate must have the same signature as the method
    ' it will call asynchronously.
    Public Delegate Function AsyncMethodCaller(ByVal callDuration As Integer, _
        <Out> ByRef threadId As Integer) As String
End Namespace

Esperar una llamada asincrónica con EndInvokeWaiting for an Asynchronous Call with EndInvoke

La manera más sencilla de ejecutar un método de forma asincrónica es empezar a ejecutar el método llamando al método BeginInvoke del delegado, hacer algún trabajo en el subproceso principal y, a continuación, llamar al método EndInvoke del delegado.The simplest way to execute a method asynchronously is to start executing the method by calling the delegate's BeginInvoke method, do some work on the main thread, and then call the delegate's EndInvoke method. EndInvoke podrían bloquear el subproceso que realiza la llamada porque no vuelve hasta que no se completa la llamada asincrónica.EndInvoke might block the calling thread because it does not return until the asynchronous call completes. Ésta es una buena técnica para utilizarla con operaciones de archivos o red.This is a good technique to use with file or network operations.

Importante

Dado que EndInvoke podría mantener un bloqueo, nunca debe llamar a este método desde los subprocesos que dan servicio a la interfaz de usuario.Because EndInvoke might block, you should never call it from threads that service the user interface.

#using <TestMethod.dll>

using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;

void main() 
{
    // The asynchronous method puts the thread id here.
    int threadId = 2546;

    // Create an instance of the test class.
    AsyncDemo^ ad = gcnew AsyncDemo();

    // Create the delegate.
    AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
       
    // Initiate the asychronous call.
    IAsyncResult^ result = caller->BeginInvoke(3000, 
        threadId, nullptr, nullptr);

    Thread::Sleep(1);
    Console::WriteLine("Main thread {0} does some work.",
        Thread::CurrentThread->ManagedThreadId);

    // Call EndInvoke to wait for the asynchronous call to complete,
    // and to retrieve the results.
    String^ returnValue = caller->EndInvoke(threadId, result);

    Console::WriteLine("The call executed on thread {0}, with return value \"{1}\".",
        threadId, returnValue);
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        public static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Call EndInvoke to wait for the asynchronous call to complete,
            // and to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations
    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            Thread.Sleep(0)
            Console.WriteLine("Main thread {0} does some work.", _
                 Thread.CurrentThread.ManagedThreadId)

            ' Call EndInvoke to Wait for the asynchronous call to complete,
            ' and to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class

End Namespace

'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".

Esperar una llamada asincrónica con WaitHandleWaiting for an Asynchronous Call with WaitHandle

Puede obtener un objeto WaitHandle utilizando la propiedad AsyncWaitHandle de IAsyncResult devuelta por BeginInvoke.You can obtain a WaitHandle by using the AsyncWaitHandle property of the IAsyncResult returned by BeginInvoke. WaitHandle se señaliza cuando finaliza la llamada asincrónica y puede esperar a que termine llamando al método WaitOne .The WaitHandle is signaled when the asynchronous call completes, and you can wait for it by calling the WaitOne method.

Si utiliza un objeto WaitHandle, puede realizar otros procesamientos adicionales antes o después de que se complete la llamada asincrónica, pero antes de llamar al método EndInvoke para recuperar los resultados.If you use a WaitHandle, you can perform additional processing before or after the asynchronous call completes, but before calling EndInvoke to retrieve the results.

Nota

El identificador de espera no se cierra automáticamente cuando llama a EndInvoke.The wait handle is not closed automatically when you call EndInvoke. Si libera todas las referencias al identificador de espera, se liberarán los recursos del sistema cuando la recolección de elementos no utilizados reclame el identificador de espera.If you release all references to the wait handle, system resources are freed when garbage collection reclaims the wait handle. Para liberar los recursos del sistema tan pronto como se deje de utilizar el identificador de espera, elimínelo llamando al método WaitHandle.Close .To free the system resources as soon as you are finished using the wait handle, dispose of it by calling the WaitHandle.Close method. La recolección de elementos no utilizados funciona más eficazmente cuando los objetos descartables se eliminan de forma explícita.Garbage collection works more efficiently when disposable objects are explicitly disposed.

#using <TestMethod.dll>

using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;

void main() 
{
    // The asynchronous method puts the thread id here.
    int threadId;

    // Create an instance of the test class.
    AsyncDemo^ ad = gcnew AsyncDemo();

    // Create the delegate.
    AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
       
    // Initiate the asychronous call.
    IAsyncResult^ result = caller->BeginInvoke(3000, 
        threadId, nullptr, nullptr);

    Thread::Sleep(0);
    Console::WriteLine("Main thread {0} does some work.",
        Thread::CurrentThread->ManagedThreadId);

    // Wait for the WaitHandle to become signaled.
    result->AsyncWaitHandle->WaitOne();

    // Perform additional processing here.
    // Call EndInvoke to retrieve the results.
    String^ returnValue = caller->EndInvoke(threadId, result);

    // Close the wait handle.
    result->AsyncWaitHandle->Close();

    Console::WriteLine("The call executed on thread {0}, with return value \"{1}\".",
        threadId, returnValue);
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Wait for the WaitHandle to become signaled.
            result.AsyncWaitHandle.WaitOne();

            // Perform additional processing here.
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            // Close the wait handle.
            result.AsyncWaitHandle.Close();

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            Thread.Sleep(0)
            Console.WriteLine("Main thread {0} does some work.", _
                Thread.CurrentThread.ManagedThreadId)
            ' Perform additional processing here and then
            ' wait for the WaitHandle to be signaled.
            result.AsyncWaitHandle.WaitOne()

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            ' Close the wait handle.
            result.AsyncWaitHandle.Close()

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class
End Namespace

'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".

Sondear la finalización de una llamada asincrónicaPolling for Asynchronous Call Completion

Puede utilizar la propiedad IsCompleted del objeto IAsyncResult devuelto por BeginInvoke para detectar el momento en que se completa la llamada asincrónica.You can use the IsCompleted property of the IAsyncResult returned by BeginInvoke to discover when the asynchronous call completes. Puede hacer esto último cuando realice la llamada asincrónica desde un subproceso que dé servicio a la interfaz de usuario.You might do this when making the asynchronous call from a thread that services the user interface. Sondear la finalización de una llamada asincrónica permite al subproceso de llamada seguirse ejecutando mientras la llamada asincrónica se ejecuta en un subproceso ThreadPool .Polling for completion allows the calling thread to continue executing while the asynchronous call executes on a ThreadPool thread.

#using <TestMethod.dll>

using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;

void main() 
{
    // The asynchronous method puts the thread id here.
    int threadId;

    // Create an instance of the test class.
    AsyncDemo^ ad = gcnew AsyncDemo();

    // Create the delegate.
    AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
       
    // Initiate the asychronous call.
    IAsyncResult^ result = caller->BeginInvoke(3000, 
        threadId, nullptr, nullptr);

    // Poll while simulating work.
    while(result->IsCompleted == false)
    {
        Thread::Sleep(250);
        Console::Write(".");
    }

    // Call EndInvoke to retrieve the results.
    String^ returnValue = caller->EndInvoke(threadId, result);

    Console::WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
        threadId, returnValue);
}

/* This example produces output similar to the following:

Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
 */
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            // Poll while simulating work.
            while(result.IsCompleted == false) {
                Thread.Sleep(250);
                Console.Write(".");
            }

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
 */
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            ' Poll while simulating work.
            While result.IsCompleted = False
                Thread.Sleep(250)
                Console.Write(".")
            End While

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            Console.WriteLine(vbCrLf & _
                "The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class
End Namespace

' This example produces output similar to the following:
'
'Test method begins.
'.............
'The call executed on thread 3, with return value "My call time was 3000.".

Ejecutar un método de devolución de llamada cuando finaliza una llamada asincrónicaExecuting a Callback Method When an Asynchronous Call Completes

Si no es necesario que el subproceso que inicia la llamada asincrónica sea el mismo que procesa los resultados, puede ejecutar un método de devolución de llamada cuando se complete la llamada.If the thread that initiates the asynchronous call does not need to be the thread that processes the results, you can execute a callback method when the call completes. El método de devolución de llamada se ejecuta en un subproceso ThreadPool .The callback method is executed on a ThreadPool thread.

Para utilizar un método de devolución de llamada, debe pasar al método BeginInvoke un delegado AsyncCallback que represente al método de devolución de llamada.To use a callback method, you must pass BeginInvoke an AsyncCallback delegate that represents the callback method. También puede pasar un objeto que contenga la información que va a utilizar el método de devolución de llamada.You can also pass an object that contains information to be used by the callback method. En el método de devolución de llamada, puede convertir IAsyncResult, que es el único parámetro del método de devolución de llamada, en un objeto AsyncResult .In the callback method, you can cast the IAsyncResult, which is the only parameter of the callback method, to an AsyncResult object. A continuación, puede utilizar la propiedad AsyncResult.AsyncDelegate para obtener el delegado que se utilizó para iniciar la llamada y, de ese modo, pueda llamar a EndInvoke.You can then use the AsyncResult.AsyncDelegate property to get the delegate that was used to initiate the call so that you can call EndInvoke.

Notas sobre el ejemplo:Notes on the example:

  • El parámetro threadId de TestMethod es un parámetro out (<Out> ByRef en Visual Basic), por lo que TestMethod nunca usa el valor de entrada.The threadId parameter of TestMethod is an out parameter ([<Out> ByRef in Visual Basic), so its input value is never used by TestMethod. Una variable ficticia se pasa a la llamada a BeginInvoke .A dummy variable is passed to the BeginInvoke call. Si el parámetro threadId fuera un parámetro ref (ByRef en Visual Basic), la variable tendría que ser un campo de nivel de clase para que pudiera pasarse a los métodos BeginInvoke y EndInvoke.If the threadId parameter were a ref parameter (ByRef in Visual Basic), the variable would have to be a class-level field so that it could be passed to both BeginInvoke and EndInvoke.

  • La información de estado que se pasa a BeginInvoke es una cadena de formato, que el método de devolución de llamada utiliza para dar formato a un mensaje de salida.The state information that is passed to BeginInvoke is a format string, which the callback method uses to format an output message. Dado que se pasa como un tipo Object, la información de estado tiene que convertirse a su tipo apropiado antes de poderse utilizar.Because it is passed as type Object, the state information must be cast to its proper type before it can be used.

  • La devolución de llamada se realiza en un subproceso ThreadPool .The callback is made on a ThreadPool thread. Los subprocesosThreadPool son subprocesos en segundo plano, que no mantienen la aplicación en ejecución si el subproceso principal finaliza, por lo que el subproceso principal del ejemplo debe permanecer en suspensión el tiempo suficiente para que la devolución de llamada finalice.ThreadPool threads are background threads, which do not keep the application running if the main thread ends, so the main thread of the example has to sleep long enough for the callback to finish.

#using <TestMethod.dll>

using namespace System;
using namespace System::Threading;
using namespace System::Runtime::Remoting::Messaging;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;

// The callback method must have the same signature as the
// AsyncCallback delegate.
void CallbackMethod(IAsyncResult^ ar) 
{
    // Retrieve the delegate.
    AsyncResult^ result = (AsyncResult^) ar;
    AsyncMethodCaller^ caller = (AsyncMethodCaller^) result->AsyncDelegate;

    // Retrieve the format string that was passed as state 
    // information.
    String^ formatString = (String^) ar->AsyncState;

    // Define a variable to receive the value of the out parameter.
    // If the parameter were ref rather than out then it would have to
    // be a class-level field so it could also be passed to BeginInvoke.
    int threadId = 0;

    // Call EndInvoke to retrieve the results.
    String^ returnValue = caller->EndInvoke(threadId, ar);

    // Use the format string to format the output message.
    Console::WriteLine(formatString, threadId, returnValue);
};

void main() 
{
    // Create an instance of the test class.
    AsyncDemo^ ad = gcnew AsyncDemo();

    // Create the delegate.
    AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
       
    // The threadId parameter of TestMethod is an out parameter, so
    // its input value is never used by TestMethod. Therefore, a dummy
    // variable can be passed to the BeginInvoke call. If the threadId
    // parameter were a ref parameter, it would have to be a class-
    // level field so that it could be passed to both BeginInvoke and 
    // EndInvoke.
    int dummy = 0;

    // Initiate the asynchronous call, passing three seconds (3000 ms)
    // for the callDuration parameter of TestMethod; a dummy variable 
    // for the out parameter (threadId); the callback delegate; and
    // state information that can be retrieved by the callback method.
    // In this case, the state information is a string that can be used
    // to format a console message.
    IAsyncResult^ result = caller->BeginInvoke(3000,
        dummy, 
        gcnew AsyncCallback(&CallbackMethod),
        "The call executed on thread {0}, with return value \"{1}\".");

    Console::WriteLine("The main thread {0} continues to execute...", 
        Thread::CurrentThread->ManagedThreadId);

    // The callback is made on a ThreadPool thread. ThreadPool threads
    // are background threads, which do not keep the application running
    // if the main thread ends. Comment out the next line to demonstrate
    // this.
    Thread::Sleep(4000);
    Console::WriteLine("The main thread ends.");
}

/* This example produces output similar to the following:

The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
 */
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // The threadId parameter of TestMethod is an out parameter, so
            // its input value is never used by TestMethod. Therefore, a dummy
            // variable can be passed to the BeginInvoke call. If the threadId
            // parameter were a ref parameter, it would have to be a class-
            // level field so that it could be passed to both BeginInvoke and 
            // EndInvoke.
            int dummy = 0;

            // Initiate the asynchronous call, passing three seconds (3000 ms)
            // for the callDuration parameter of TestMethod; a dummy variable 
            // for the out parameter (threadId); the callback delegate; and
            // state information that can be retrieved by the callback method.
            // In this case, the state information is a string that can be used
            // to format a console message.
            IAsyncResult result = caller.BeginInvoke(3000,
                out dummy, 
                new AsyncCallback(CallbackMethod),
                "The call executed on thread {0}, with return value \"{1}\".");

            Console.WriteLine("The main thread {0} continues to execute...", 
                Thread.CurrentThread.ManagedThreadId);

            // The callback is made on a ThreadPool thread. ThreadPool threads
            // are background threads, which do not keep the application running
            // if the main thread ends. Comment out the next line to demonstrate
            // this.
            Thread.Sleep(4000);

            Console.WriteLine("The main thread ends.");
        }
        
        // The callback method must have the same signature as the
        // AsyncCallback delegate.
        static void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult) ar;
            AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;

            // Retrieve the format string that was passed as state 
            // information.
            string formatString = (string) ar.AsyncState;

            // Define a variable to receive the value of the out parameter.
            // If the parameter were ref rather than out then it would have to
            // be a class-level field so it could also be passed to BeginInvoke.
            int threadId = 0;

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);

            // Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
 */
Imports System
Imports System.Threading
Imports System.Runtime.Remoting.Messaging

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        
        Shared Sub Main() 

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)

            ' The threadId parameter of TestMethod is an <Out> parameter, so
            ' its input value is never used by TestMethod. Therefore, a dummy
            ' variable can be passed to the BeginInvoke call. If the threadId
            ' parameter were a ByRef parameter, it would have to be a class-
            ' level field so that it could be passed to both BeginInvoke and 
            ' EndInvoke.
            Dim dummy As Integer = 0

            ' Initiate the asynchronous call, passing three seconds (3000 ms)
            ' for the callDuration parameter of TestMethod; a dummy variable 
            ' for the <Out> parameter (threadId); the callback delegate; and
            ' state information that can be retrieved by the callback method.
            ' In this case, the state information is a string that can be used
            ' to format a console message.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                dummy, _
                AddressOf CallbackMethod, _
                "The call executed on thread {0}, with return value ""{1}"".")

            Console.WriteLine("The main thread {0} continues to execute...", _
                Thread.CurrentThread.ManagedThreadId)

            ' The callback is made on a ThreadPool thread. ThreadPool threads
            ' are background threads, which do not keep the application running
            ' if the main thread ends. Comment out the next line to demonstrate
            ' this.
            Thread.Sleep(4000)

            Console.WriteLine("The main thread ends.")
        End Sub

        ' The callback method must have the same signature as the
        ' AsyncCallback delegate.
        Shared Sub CallbackMethod(ByVal ar As IAsyncResult)
            ' Retrieve the delegate.
            Dim result As AsyncResult = CType(ar, AsyncResult)
            Dim caller As AsyncMethodCaller = CType(result.AsyncDelegate, AsyncMethodCaller)

            ' Retrieve the format string that was passed as state 
            ' information.
            Dim formatString As String = CType(ar.AsyncState, String)

            ' Define a variable to receive the value of the <Out> parameter.
            ' If the parameter were ByRef rather than <Out> then it would have to
            ' be a class-level field so it could also be passed to BeginInvoke.
            Dim threadId As Integer = 0

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, ar)

            ' Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue)
        End Sub
    End Class
End Namespace

' This example produces output similar to the following:
'
'The main thread 1 continues to execute...
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
'The main thread ends.

Vea tambiénSee also