首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AsyncCallback到BackgroundWorker

AsyncCallback到BackgroundWorker
EN

Stack Overflow用户
提问于 2014-01-29 20:59:48
回答 2查看 688关注 0票数 2

我想使用.NET-FTP Libary (http://netftp.codeplex.com)。libary提供了BeginOpenRead(string,AsyncCallback,object)来使用异步编程模型下载内容。回调的实现与示例基本相同:

代码语言:javascript
复制
static void BeginOpenReadCallback(IAsyncResult ar) {
        FtpClient conn = ar.AsyncState as FtpClient;

        try {
            if (conn == null)
                throw new InvalidOperationException("The FtpControlConnection object is null!");

            using (Stream istream = conn.EndOpenRead(ar)) {
                byte[] buf = new byte[8192];

                try {
                    DateTime start = DateTime.Now;

                    while (istream.Read(buf, 0, buf.Length) > 0) {
                        double perc = 0;

                        if (istream.Length > 0)
                            perc = (double)istream.Position / (double)istream.Length;

                        Console.Write("\rTransferring: {0}/{1} {2}/s {3:p}         ",
                                      istream.Position.FormatBytes(),
                                      istream.Length.FormatBytes(),
                                      (istream.Position / DateTime.Now.Subtract(start).TotalSeconds).FormatBytes(),
                                      perc);
                    }
                }
                finally {
                    Console.WriteLine();
                    istream.Close();
                }
            }
        }
        catch (Exception ex) {
            Console.WriteLine(ex.ToString());
        }
        finally {
            m_reset.Set();
        }
    }

在异步方法的工作完成之后,如果触发一个已完成的事件(由启动异步方法的线程以避免UI问题)将结果传递给主线程,那就太好了。就像BackgroundWorker一样(使用RunWorkerCompleted)。

我怎么能意识到这一点?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-29 21:57:45

尝试将APM模式转换为水龙头模式(更多信息):

代码语言:javascript
复制
static public Task<Stream> OpenReadAsync(FtpClient ftpClient, string url)
{
    return Task.Factory.FromAsync(
         (asyncCallback, state) =>
             ftpClient.BeginOpenRead(url, asyncCallback, state),
         (asyncResult) =>
             ftpClient.EndOpenRead((asyncResult));
}

然后可以使用async/await,不必担心同步上下文:

代码语言:javascript
复制
Stream istream = await OpenReadAsync(ftpClient, url); 

此外,您还可以使用Stream.ReadAsync

代码语言:javascript
复制
while (await istream.ReadAsync(buf, 0, buf.Length) > 0) 
{
    // ...
}

BackgroundWorker被基于任务的API所取代,所以它可能是双赢的情况(更多信息:Task.Run对BackgroundWorker这里)。

UPDATE --如果您在VS2012+中工作,可以使用Microsoft.Bcl.Async来针对.NET 4.0,并且仍然使用现代语言和TPL特性,比如async/await。我已经经历过了,我强烈推荐它,因为它使得将来移植到.NET 4.5非常容易。

否则,您可以使用Task.ContinueWith(callback, TaskScheduler.FromCurrentSynchronizationContext())在UI线程上继续。这是一个相关实例

票数 2
EN

Stack Overflow用户

发布于 2014-01-29 21:29:12

最简单的方法是将SynchronizationContext传递给BeginOpenRead并在回调中使用它。

代码语言:javascript
复制
private class StateHolder
{
    public StateHolder(FtpClient client, SynchronizationContext context)
    {
        Client = client;
        Context = context;

        //SynchronizationContext.Current can return null, this creates a new context that posts to the Thread Pool if called.
        if(Context == null)
            Context = new SynchronizationContext();
    }

    public FtpClient Client {get; private set;}
    public SynchronizationContext Context {get; private set;}
}

//...

ftpClient.BeginOpenRead(someString,BeginOpenReadCallback, new StateHolder(ftpClient, SynchronizationContext.Current));

然后在回调中使用传入的状态对象。

代码语言:javascript
复制
void BeginOpenReadCallback(IAsyncResult ar) 
{
    StateHolder state = ar.AsyncState as StateHolder;
    FtpClient conn = state.client;

    //... Everything else the same in the function.

    //state.Context can't be null because we set it in the constructor.
    state.Context.Post(OnCompleted, conn);

}

protected virtual void OnCompleted(object state) //I use object instead of FtpClient to make the "state.Context.Post(OnCompleted, conn);" call simpler.
{
    var conn = state as FtpClient;
    var tmp = Completed; //This is the event people subscribed to.
    (tmp != null)
    {
        tmp(this, new CompletedArgs(conn)); //Assumes you followed the standard Event pattern and created the necessary classes.
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21442523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档