代码之家  ›  专栏  ›  技术社区  ›  Davy8

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

  •  11
  • Davy8  · 技术社区  · 16 年前

    我们有一个常见的场景,其中我们有一个异步执行某些操作的方法,并在完成后引发一个事件。

    有时我们希望它是同步完成的,所以我们有类似这样的代码:

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

    有没有一种方法可以写一个助手方法来完成这个任务?我可以传入要执行的操作,但我不确定如何传入一些内容,这些内容使helper方法知道要侦听哪个事件,因为它看起来不像可以作为参数传入事件处理程序。

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

    似乎有些混淆,这是某个对象类的示例:

    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 回复  |  直到 16 年前
        1
  •  4
  •   Jeff Cyr    16 年前

    我会考虑实施 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上找到通用异步结果类的实现。

    编辑:

    正如您希望保留当前设计一样,如果所有对象只能有一个异步操作,那么您可以定义一个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();
    }
    
        2
  •  3
  •   MindFold    16 年前

    如果我明白你的意思,你可以用下面的方法简单地使用委托, 为函数调用创建委托,让我们调用它

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

    仅此而已,您可以通过在完成后添加另一个要运行的函数委托或类似的方法使其变得更复杂。

    享受吧!