Pregunta

I am in the process of refactoring "synchronous" code (i.e. uses Windows events to wait until some other thread finished doing something) to "asynchronous" code (using delegates to implement a callback mechanism).

In the sync code, I sometimes have local variables that I need to use after the wait is over. When code like that goes async, those local variables are lost (the callback handler can't access them). I can store them as class attributes, but it feels wasteful.

In C++, I use std::bind to work around this. I just add as many parameters as local variables needed to the callback handler, and bind them when I call the async method. For example, let's say that the async method callback receives an object of type CallbackParam and the caller uses two local variables of type LocalA and LocalB.

void AsyncClass::MethodWhichCallsAsyncMethod(){
    LocalA localVarA;
    LocalB localVarB;
    // OnAsyncMethodDone will need localVarA and localVarB, so we bind them
    AsyncMethod( std::bind( &AsyncClass::OnAsyncMethodDone, this, std::placeholders::_1, localVarA, localVarB ) );
}

void AsynClass::AsyncMethod( std::function<void(CallbackParam)> callback ){
    CallbackParam result;
    //Compute result...
    if( callback )
        callback( result );
}

void AsyncClass::OnAsyncMethodDone( CallbackParam p, LocalA a, LocalB b ){
   //Do whatever needs to be done
}

Is there some sort of equivalent to this in C# and VB.NET? Using delegates or something else?

UPDATE: For completeness' sake, here is the C# equivalent of my example based on @lasseespeholt's answer:

using System;

public class AsyncClass {

        public void MethodWhichCallsAsyncMethod() {
            var a = new LocalA();
            var b = new LocalB();
            //Anonymous callback handler (equivalent to AsyncClass::OnAsyncMethodDone)
            Action<CallbackParam> callback = result => {
                //Do what needs to be done; result, a and b can be accessed
            };
            AsyncMethod( callback );
        }

        private void AsyncMethod( Action<CallbackParam> callback ) {
            var result = new CallbackParam();
            //Compute result...
            if( callback != null )
                callback( result );
        }
}
¿Fue útil?

Solución

UPDATE: This should almost certainly not be used. Use the async/await keywords in C#

You can exploit closures like the following:

void MethodWhichCallsAsyncMethod()
{
    int foo = 1;

    AsyncCallback callback = result =>
    {
        Console.WriteLine(foo); // Access to foo
    };

    AsyncMethod(callback);
}

void AsyncMethod(AsyncCallback callback)
{
    IAsyncResult result = null; // Compute result
    callback(result);
}

The compiler generates a class which contains "foo" so you don't save anything with this approach, but it's clean.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top