views:

153

answers:

2

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));
    }
}
+2  A: 

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!

MindFold
If I'm not mistaken that assumes you already have a synchronous function doesn't it? When I call `someobject.PerformAsyncAction();` it queues up the action and returns right away, I don't see if I passed my function to your method it would know when the action is actually done.
Davy8
When the action completes, it calls the callback which 'sets' the ManualResetEvent. The main function won't return until the ManualResetEvent is 'set'.
Foole
How does it know when the action is complete? All the Action function does is send off a message and then returns immediately.
Davy8
That was @Foole btw. I know the callback calls set on the resetevent, but doesn't the callback get called when `func` returns?
Davy8
@Davy8: No. The callback gets called when func finishes its async task.
Foole
@Foole how does it know when it's complete if it's not complete when the method returns?
Davy8
+2  A: 

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();
}
SelflessCoder
I'm shooting for a solution that doesn't involve modifying the class of `someobject` The current pattern exists in dozens of classes in our system already.
Davy8
Edited question with hopefully a better explaination
Davy8
Edited the answer as well
SelflessCoder
There are in fact multiple async actions so it looks like it'll have to be implemented everywhere. It's actually on an interface so it'd need to be added to the interface and implemented by multiple classes. It seems crazy that there's no way to pass a specific event as a parameter to a method. It'd still be following the same rules as an event outside of the declaring class in that you'd only be able to add or remove handlers and not be able to raise or call any other methods on it.
Davy8
I'll accept this if there's no other suitable answers today
Davy8