Я нахожусь в процессе рефакторинга «синхронного» кода (то есть использует события Windows, чтобы дождаться, пока какой-то другой поток завершит выполнение чего-либо) в «асинхронный» код (используя делегатов для реализации механизма обратного вызова).
В коде синхронизации у меня иногда есть локальные переменные, которые мне нужно использовать после окончания ожидания. Когда такой код становится асинхронным, эти локальные переменные теряются (обработчик обратного вызова не может получить к ним доступ). Я могу хранить их как атрибуты класса, но это расточительно.
В C ++ я использую std::bind
обойти это. Я просто добавляю столько параметров, сколько локальных переменных, необходимых для обработчика обратного вызова, и связываю их при вызове асинхронного метода. Например, допустим, что обратный вызов асинхронного метода получает объект типа CallbackParam
и вызывающая сторона использует две локальные переменные типа LocalA
а также 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
}
Есть ли какой-то эквивалент этого в C # и VB.NET? Использование делегатов или что-то еще?
ОБНОВИТЬДля полноты картины вот эквивалент C # моего примера, основанный на ответе @ lasseespeholt:
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 );
}
}
ОБНОВЛЕНИЕ: Это почти наверняка не должно использоваться. Используйте ключевые слова async / await в C #
Вы можете использовать замыкания следующим образом:
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);
}
Компилятор генерирует класс, который содержит «foo», поэтому вы ничего не сохраняете с этим подходом, но он чистый.
Других решений пока нет …