是否有一种同步异步方法的通用方法?

时间:2010-02-12 22:58:53

标签: c# asynchronous

我们有这种常见的场景,我们有一个方法可以异步执行某些操作,并在完成时引发一个事件。

有时候我们希望它同步完成,所以我们的代码看起来与此类似:

ManualResetEvent reset = new ManualResetEvent(false);
someobject.AsyncActionDone += (sender, args) => reset.Set();
someobject.PerformAsyncAction();
reset.WaitOne();

有没有办法编写辅助方法来执行此操作?我可以传递Action来执行,但我不确定如何传递一些让helper方法知道要侦听哪个事件的东西,因为它看起来不像你可以将EventHandler作为参数传递。

最好是不需要反射的解决方案

似乎有些混乱,这是某些对象类的样本:

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 个答案:

答案 0 :(得分:4)

我会考虑在执行异步操作的对象中实现Asynchronous Design Pattern

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();
}

使用此模式,您可以灵活地在对象上进行多个并发异步操作。

注意:您可以在Web上轻松找到通用AsyncResult类的实现。

修改

如果你想保留当前的设计,如果你的所有对象只能有一个异步操作,那么你可以定义一个IAsyncOperation接口并在你的所有对象中实现它。

public interface IAsyncOperation
{
    event EventHandler AsyncActionDone;
    void PerformAsyncAction();
}

然后你可以:

public static CallSynchronously(IAsyncOperation asyncOperation)
{
    ManualResetEvent reset = new ManualResetEvent(false);
    asyncOperation.AsyncActionDone += (sender, args) => reset.Set();
    asyncOperation.PerformAsyncAction();
    reset.WaitOne();
}

如果你的对象可以包含多个异步操作,那么没有反射我认为没有办法实现你想做的事情,但你仍然可以定义包装ManualResetEvent的所有异步操作的同步版本。

public void PerformAction()
{
    ManualResetEvent reset = new ManualResetEvent(false);
    this.AsyncActionDone += (sender, args) => reset.Set();
    this.PerformAsyncAction();
    reset.WaitOne();
}

答案 1 :(得分:3)

如果我抓住你的漂移,你可以通过以下方式简单地使用代表, 为你的函数调用创建一个委托,让我们调用它

    public delegate string AsyncDelegate();

然后,创建一个这样的代理函数:

 public static void ExecuteSync(AsyncDelegate func)
    {
        ManualResetEvent reset = new ManualResetEvent(false);
        int threadId;
        func.BeginInvoke((a)=>reset.Set(), null);
        reset.WaitOne();
    }

总而言之,你可以通过在完成后添加另一个函数委托来使其更复杂一些......或者类似的事情。

享受!