Самый простой способ асинхронно реализовать синхронный метод - это поместить его в делегат и использовать методы BeginInvoke
и EndInvoke
в полученном делегате. Это запустит синхронный метод в потоке потоков, а BeginInvoke
вернет реализацию IAsyncResult
, так что вам не нужно реализовывать его внутренности. Однако вам нужно переправить немного дополнительных данных в IAsyncResult
, возвращаемый IOperationInvoker.InvokeEnd
. Это можно легко сделать, создав реализацию IAsyncResult
, которая делегирует все внутреннему IAsyncResult
, но имеет дополнительное поле для хранения делегата, так что когда экземпляр IAsyncResult
передается в InvokeEnd
, вы можете получить доступ к делегату для вызова EndInvoke
на нем.
Однако, после более внимательного прочтения вашего вопроса, я вижу, что вам нужно использовать явную ветку с настройками COM и т. Д.
Что вам нужно сделать, так это правильно реализовать IAsyncResult
. Из этого следует почти все, поскольку IAsyncResult
будет содержать все биты, необходимые для синхронизации.
Вот очень простая, но не очень эффективная реализация IAsyncResult
. Он включает в себя все необходимые функции: передачу аргументов, событие синхронизации, реализацию обратного вызова, распространение исключений из асинхронной задачи и возврат результата.
using System;
using System.Threading;
class MyAsyncResult : IAsyncResult
{
object _state;
object _lock = new object();
ManualResetEvent _doneEvent = new ManualResetEvent(false);
AsyncCallback _callback;
Exception _ex;
bool _done;
int _result;
int _x;
public MyAsyncResult(int x, AsyncCallback callback, object state)
{
_callback = callback;
_state = state;
_x = x; // arbitrary argument(s)
}
public int X { get { return _x; } }
public void SignalDone(int result)
{
lock (_lock)
{
_result = result;
_done = true;
_doneEvent.Set();
}
// never invoke any delegate while holding a lock
if (_callback != null)
_callback(this);
}
public void SignalException(Exception ex)
{
lock (_lock)
{
_ex = ex;
_done = true;
_doneEvent.Set();
}
if (_callback != null)
_callback(this);
}
public object AsyncState
{
get { return _state; }
}
public WaitHandle AsyncWaitHandle
{
get { return _doneEvent; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public int Result
{
// lock (or volatile, complex to explain) needed
// for memory model problems.
get
{
lock (_lock)
{
if (_ex != null)
throw _ex;
return _result;
}
}
}
public bool IsCompleted
{
get { lock (_lock) return _done; }
}
}
class Program
{
static void MyTask(object param)
{
MyAsyncResult ar = (MyAsyncResult) param;
try
{
int x = ar.X;
Thread.Sleep(1000); // simulate lengthy work
ar.SignalDone(x * 2); // demo work = double X
}
catch (Exception ex)
{
ar.SignalException(ex);
}
}
static IAsyncResult Begin(int x, AsyncCallback callback, object state)
{
Thread th = new Thread(MyTask);
MyAsyncResult ar = new MyAsyncResult(x, callback, state);
th.Start(ar);
return ar;
}
static int End(IAsyncResult ar)
{
MyAsyncResult mar = (MyAsyncResult) ar;
mar.AsyncWaitHandle.WaitOne();
return mar.Result; // will throw exception if one
// occurred in background task
}
static void Main(string[] args)
{
// demo calling code
// we don't need state or callback for demo
IAsyncResult ar = Begin(42, null, null);
int result = End(ar);
Console.WriteLine(result);
Console.ReadLine();
}
}
Для правильности важно, чтобы клиентский код не мог видеть реализацию IAsyncResult
, в противном случае он мог бы обращаться к таким методам, как SignalException
, ненадлежащим образом или читать Result
преждевременно. Класс можно сделать более эффективным, если не создавать реализацию WaitHandle
(в данном примере ManualResetEvent
), если в этом нет необходимости, но это сложно сделать на 100% правильно. Кроме того, Thread
и ManualResetEvent
могут и должны быть удалены в реализации End
, как это должно быть сделано со всеми объектами, которые реализуют IDisposable
. И, очевидно, End
должен проверить, чтобы убедиться, что он получил реализацию правильного класса, чтобы получить более приятное исключение, чем исключение приведения. Я пропустил эти и другие детали, поскольку они затеняют основную механику асинхронной реализации.