Reputation: 31586
We have this common scenario where we have a method that performs some action asyncronously and raises an event when it's done.
There are times where we want it done synchronously instead so we have code that looks similar to this:
ManualResetEvent reset = new ManualResetEvent(false);
someobject.AsyncActionDone += (sender, args) => reset.Set();
someobject.PerformAsyncAction();
reset.WaitOne();
Is there a way to write a helper method to do this? I can pass in the Action to perform, but I'm not sure how to pass in something that lets the helper method know which event to listen to since it doesn't look like you can pass in an EventHandler as a parameter.
Preferably a solution that doesn't require reflection
There seems to be some confusion, this is a sample of what someobject's class is like:
public class SomeClass
{
private ExternalServer someServerOverTheNetwork = new ExternalServer();
public event EventHandler AsyncActionDone;
public Data SomeData { get; set; }
public void PerformAsyncAction()
{
someServerOverTheNetwork.GetSomeData(OnDataRetrived);
}
public Data OnDataRetrived(Data someData)
{
AsyncActionDone(this, new DataEventArgs(someData));
}
}
Upvotes: 11
Views: 4599
Reputation: 4864
I would consider implementing the Asynchronous Design Pattern in the objects that performs asynchronous operation.
public object Operation(object arg)
{
var ar = BeginOperation(arg, null, null);
return EndOperation(ar);
}
public IAsyncResult BeginOperation(object arg, AsyncCallback asyncCallback, object state)
{
AsyncResult asyncResult = new AsyncResult(asyncCallback, state);
// Lauch the asynchronous operation
return asyncResult;
}
private void LaunchOperation(AsyncResult asyncResult)
{
// Do something asynchronously and call OnOperationFinished when finished
}
private void OnOperationFinished(AsyncResult asyncResult, object result)
{
asyncResult.Complete(result);
}
public object EndOperation(IAsyncResult asyncResult)
{
AsyncResult ar = (AsyncResult)asyncResult;
return ar.EndInvoke();
}
With this pattern you have the flexibility of having multiple concurrent asynchronous operation on your object.
Note: You can easily find an implementation of a generic AsyncResult class on the web.
Edit:
As you want to keep the current design, if all your object can only have one asynchronous operation, then you could define an IAsyncOperation interface and implement it in all your object.
public interface IAsyncOperation
{
event EventHandler AsyncActionDone;
void PerformAsyncAction();
}
Then you could have:
public static CallSynchronously(IAsyncOperation asyncOperation)
{
ManualResetEvent reset = new ManualResetEvent(false);
asyncOperation.AsyncActionDone += (sender, args) => reset.Set();
asyncOperation.PerformAsyncAction();
reset.WaitOne();
}
If your objects can contain multiple asynchronous operation, then without reflection I think there is no way to achieve what you want to do, but you could still define a synchronous version of all asynchronous operation that wraps the ManualResetEvent.
public void PerformAction()
{
ManualResetEvent reset = new ManualResetEvent(false);
this.AsyncActionDone += (sender, args) => reset.Set();
this.PerformAsyncAction();
reset.WaitOne();
}
Upvotes: 4
Reputation: 771
If i catch your drift, you can simply use delegates in the following way, create a delegate for you function call, lets call it
public delegate string AsyncDelegate();
then, create a proxy function like this:
public static void ExecuteSync(AsyncDelegate func)
{
ManualResetEvent reset = new ManualResetEvent(false);
int threadId;
func.BeginInvoke((a)=>reset.Set(), null);
reset.WaitOne();
}
Thats all, you can make it a bit more complex by adding another function delegate to run after completion or something like that..
Enjoy!
Upvotes: 3