2011-05-18 27 views
53

Sé cómo hacer métodos Async pero digo que tengo un método que hace mucho trabajo y luego devuelve un valor booleano.¿Cómo hacer que un método asíncrono devuelva un valor?

¿Cómo devuelvo el valor booleano en la devolución de llamada?

Aclaración:

public bool Foo(){ 
    Thread.Sleep(100000); // Do work 
    return true; 
} 

Quiero ser capaz de hacer esto asíncrona.

Respuesta

39

Hay algunas maneras de hacer eso ... el más simple es tener el método asíncrono también hacer la operación de seguimiento. Otro método popular es pasar de una devolución de llamada, es decir

void RunFooAsync(..., Action<bool> callback) { 
    // do some stuff 
    bool result = ... 

    if(callback != null) callback(result); 
} 

Otro enfoque sería elevar un evento (con el resultado en los datos de eventos-args) cuando la operación asincrónica es completa.

Además, si está utilizando el TPL, puede utilizar ContinueWith:

Task<bool> outerTask = ...; 
outerTask.ContinueWith(task => 
{ 
    bool result = task.Result; 
    // do something with that 
}); 
+0

Buen ejemplo simple de aproximación de devolución de llamada – DRapp

1

Utilice un BackgroundWorker. Le permitirá recibir devoluciones de llamada al finalizar y le permitirá seguir el progreso. Puede establecer el valor de Resultado en los argumentos del evento en el valor resultante.

public void UseBackgroundWorker() 
    { 
     var worker = new BackgroundWorker(); 
     worker.DoWork += DoWork; 
     worker.RunWorkerCompleted += WorkDone; 
     worker.RunWorkerAsync("input"); 
    } 

    public void DoWork(object sender, DoWorkEventArgs e) 
    { 
     e.Result = e.Argument.Equals("input"); 
     Thread.Sleep(1000); 
    } 

    public void WorkDone(object sender, RunWorkerCompletedEventArgs e) 
    { 
     var result = (bool) e.Result; 
    } 
+0

Un trabajador de fondo es contraproducente aquí. ¿No conoces AutoResetEvent/ManualResetEvent? –

+1

@the_drow No estoy de acuerdo con eso; un BackgroundWorker y el evento RunWorkerCompleted son un enfoque perfectamente bueno aquí –

+0

@the_drow - no, yo no. Veré lo que puedo aprender al respecto. Pero si pudieras explicar por qué crees que esto es contraproducente, me gustaría entender. – NerdFury

-1

Se debe utilizar la EndXXX de su método asíncrono para devolver el valor. EndXXX debe esperar hasta que haya un resultado usando WaitHandle de IAsyncResult y luego regresar con el valor.

90

De C# 5.0, puede especificar el método que se

public async Task<bool> doAsyncOperation() 
{ 
    // do work 
    return true; 
} 

bool result = await doAsyncOperation(); 
+19

Para cualquier otra persona que le importe, para obtener los resultados, debería usar 'bool result = await doAsyncOperation();' –

+1

Siempre que vaya a utilizar la palabra clave "await" debe estar dentro de un método que ha sido marcado con, como mínimo, "asincrónico". Originalmente, pensé que solo el método de trabajo debía marcarse de esta manera. Por ejemplo, incluso si su método de llamada no devuelve nada, debe llamarlo "async void MyCallerMethod" –

+0

Sí, pero la molesta advertencia de que el método se ejecutará sincrónicamente – KingOfHypocrites

3

Probablemente la forma más sencilla de hacerlo es crear un delegado y luego BeginInvoke, seguido de una espera en algún momento en el futuro, y un EndInvoke .

public bool Foo(){ 
    Thread.Sleep(100000); // Do work 
    return true; 
} 

public SomeMethod() 
{ 
    var fooCaller = new Func<bool>(Foo); 
    // Call the method asynchronously 
    var asyncResult = fooCaller.BeginInvoke(null, null); 

    // Potentially do other work while the asynchronous method is executing. 

    // Finally, wait for result 
    asyncResult.AsyncWaitHandle.WaitOne(); 
    bool fooResult = fooCaller.EndInvoke(asyncResult); 

    Console.WriteLine("Foo returned {0}", fooResult); 
} 
+0

El AsyncWaitHandle es un WaitHandle. No tiene un método WaitOne(). Debes arrojarlo a lo que sea que tenga para esperar su finalización. –

+0

@the_drow: le recomendamos echar un vistazo a este ejemplo: http://msdn.microsoft.com/en-us/library/system.iasyncresult.asyncwaithandle.aspx. También eche un vistazo a la documentación para el método 'WaitHandle.WaitOne': http://msdn.microsoft.com/en-us/library/58195swd.aspx –

+1

O podría simplemente pegar ese código en un programa C# y probarlo . Parecía funcionar para mí. –

1

Tal vez se puede tratar de un delegado BeginInvoke que apuntan a su método de este modo:

 


    delegate string SynchOperation(string value); 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      BeginTheSynchronousOperation(CallbackOperation, "my value"); 
      Console.ReadLine(); 
     } 

     static void BeginTheSynchronousOperation(AsyncCallback callback, string value) 
     { 
      SynchOperation op = new SynchOperation(SynchronousOperation); 
      op.BeginInvoke(value, callback, op); 
     } 

     static string SynchronousOperation(string value) 
     { 
      Thread.Sleep(10000); 
      return value; 
     } 

     static void CallbackOperation(IAsyncResult result) 
     { 
      // get your delegate 
      var ar = result.AsyncState as SynchOperation; 
      // end invoke and get value 
      var returned = ar.EndInvoke(result); 

      Console.WriteLine(returned); 
     } 
    } 
 

A continuación, utilice el valor en el método que envió como AsyncCallback para continuar ..

Cuestiones relacionadas