如何使用Delegate / Callback编写相同的代码?

时间:2017-05-24 04:26:12

标签: c# winforms delegates async-await

这是一个非常简单的示例,可以在互联网上找到 Async / Await 概念,我想知道如何使用开始/结束调用来实现这个小逻辑? 我需要做的就是使用两种方法( Async / Await和delegates )准备一个复杂的逻辑,所以我想从一个基本的工作流程开始。

int countCharacters()
    {

        int count = 0;
        using (StreamReader reader= new StreamReader("D:\\Data.txt"))
        {
            string content = reader.ReadToEnd();
            count = content.Length;
            Thread.Sleep(5000);
        }
            return count; 
    }
    private async void btnProcessFIle_Click(object sender, EventArgs e)
    {
        Task<int> task = new Task<int>(countCharacters);
        task.Start();
        int count = await task;
        lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString();


    }

3 个答案:

答案 0 :(得分:2)

  

这是一个非常简单的例子,可以在互联网上找到Async / Await概念

这是一个非常糟糕的例子。

它使用任务构造函数和Start,这是一个明确的禁忌(实际上有没有有效用例)。

它还在&#34; async示例&#34;中的后台线程上同步使用文件系统。

如果你想要一个如何异步使用同步(例如,CPU绑定)代码的例子,那么这是一个更好的例子,几乎可以做同样的事情:

int countCharacters()
{
  Thread.Sleep(5000);
  return 13;
}

private async void btnProcessFIle_Click(object sender, EventArgs e)
{
  var count = await Task.Run(() => countCharacters());
  lblCount.Text = "No. of characters in file=" + count;
}

请注意,这是如何异步调用UI线程中的CPU绑定代码的示例 - 不是&#34;异步概念& #34;

  

我想知道如何使用Begin / End Invoke实现这个小逻辑?

由于您的工作是在后台线程上同步工作,这实际上非常简单; you can just use Delegate.BeginInvoke而不是创建自己的IAsyncResult(这是关于APM的非常难的部分 - 如果你确实需要实现它,请参阅&#34;实现CLR异步编程模型&#34;在{ {3}})。

但是既然你可以使用Delegate.BeginInvoke,那就非常简单了:

private void btnProcessFIle_Click(object sender, EventArgs e)
{
  var ui = SynchronizationContext.Current;
  Func<int> d = countCharacters;
  d.BeginInvoke(CountCharactersCallback, ui);
}

private void CountCharactersCallback(IAsyncResult ar) 
{
  var d = (Func<int>) ((AsyncResult) ar).AsyncDelegate;
  var ui = (SynchronizationContext) ar.AsyncState;
  try
  {
    var count = d.EndInvoke(ar);
    ui.Post(CountCharactersComplete, count);
  }
  catch (Exception ex)
  {
    var edi = ExceptionDispatchInfo.Capture(ex);
    ui.Post(CountCharactersError, state);
  }
}

private void CountCharactersComplete(object state)
{
  var count = (int) state;
  lblCount.Text = "No. of characters in file=" + count;
}

private void CountCharactersError(object state)
{
  var edi = (ExceptionDispatchInfo)state;
  edi.Throw();
}

注意:

  • CountCharactersCallback是一个&#34;裸露的回调&#34;。从CountCharactersCallback传播的任何异常都表示发生了灾难性错误。
  • 特别是,必须注意不要允许EndInvoke的异常传播出BeginInvoke回调。这是一个常见的错误。
  • 我使用SynchronizationContext同步回UI线程。这与await的行为相同。
  • 我使用ExceptionDispatchInfo来保留跨线程的异常堆栈跟踪(不需要包装器异常)。
  • CountCharactersError只是直接在消息循环上引发异常。这与async void的行为相同。

答案 1 :(得分:0)

功能BeginInvoke可以访问非UI线程中的UI元素,因此您需要像这样更改代码:

for(var k=0; k < mdmid_array_implode_array_st.length; k++){
var mdmid_arr=mdmid_array_implode_array_st[k];
pool.query("select sum(cnt_deal_amt) as cnt_deal_amt from crm_clients_feedback_log where cnt_mdm_id IN ("+mdmid_arr+") ORDER BY cnt_mdm_id ASC",function(dealerr,dealrslt){
dealrslt_sa=dealrslt[0].cnt_deal_amt;
console.log(dealrslt);
})
}

OUtPUT:
[ RowDataPacket { cnt_deal_amt: 512529 } ]
[ RowDataPacket { cnt_deal_amt: 33000 } ]
[ RowDataPacket { cnt_deal_amt: null } ]
[ RowDataPacket { cnt_deal_amt: 1000 } ]
[ RowDataPacket { cnt_deal_amt: null } ]
[ RowDataPacket { cnt_deal_amt: 43600 } ]
[ RowDataPacket { cnt_deal_amt: 0 } ]
[ RowDataPacket { cnt_deal_amt: 0 } ]
[ RowDataPacket { cnt_deal_amt: 9500 } ]
[ RowDataPacket { cnt_deal_amt: null } ]
[ RowDataPacket { cnt_deal_amt: null } ]
[ RowDataPacket { cnt_deal_amt: 11500 } ]

答案 2 :(得分:-1)

没有异步/等待的代码。您不需要使用BeginInvoke,因为您可以使用curl

捕获上下文
TaskScheduler.FromCurrentSynchronizationContext()

如果你真的想使用BeginInvoke我想你可以写

int countCharacters()
    {

        int count = 0;
        using (StreamReader reader= new StreamReader("D:\\Data.txt"))
        {
            string content = reader.ReadToEnd();
            count = content.Length;
            Thread.Sleep(5000);
        }
            return count; 
    }


    private  void btnProcessFIle_Click(object sender, EventArgs e)
    {
        Task<int> task = new Task<int>(countCharacters);
        task.Start();
        var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        task.ContinueWith(count =>{

                 lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString();   
        }, uiScheduler);
    }