【问题标题】:Confused how AsyncCallback works对 AsyncCallback 的工作方式感到困惑
【发布时间】:2015-08-14 17:52:51
【问题描述】:

我无法理解异步回调的工作原理。我在一个单独的类中有一个方法(调用这个类“Foo”),它需要我传入一个 asynccallback 方法和一个对象。

这个方法应该是下载一些内容作为字符串。

public void sampleFunction(AsyncCallback callback, object x)
{
    //download some content as a string
}

然后我有我的 asynccallback 方法和我调用上述方法的方法:

public static void test(IAsyncResult result)
{
     Console.WriteLine("Reached");

     //Is result the string that should have been downloaded? Confused
     Console.WriteLine(result); 
}

public static void sampleFunction2()
{
    Foo z;
    object t = "hello";
    AsyncCallback callback = new AsyncCallback(test);
    z.sampleFunction(callback, t);
 }

调用 sampleFunction2 后,控制台上没有任何内容。我在做什么/理解错了?

【问题讨论】:

  • result的类型是什么?
  • @SKLAK 如果您不确定异步是如何工作的,那么请进行谷歌搜索并阅读此处发布的答案以获取解释stackoverflow.com/questions/24953808/…
  • @MrLister 是一个只包含一个取消异步操作的方法的接口。
  • 如果您在第一次调用Console.WriteLine 时设置断点,调试器会告诉您什么?关于IAsynchResult,文档告诉你什么?
  • @KenWhite 它甚至没有到达断点,所以没有到达方法

标签: c# asynchronous


【解决方案1】:

我会使用 async await 关键字,而不是使用 AsyncCallback 的旧(但仍然有效)方法。

public async Task SampleFunction(object x)
{
    await DownloadAsync(); //Download your string using await
    //await will block here until "DownloadAsync" returns. It will return control to the calling method and return here when the await finishes (or comes back to finish the method).
}

public async static CallerMethod()
{
    await SampleFunction(yourObject);
    //The code will continue here while the string is downloading and it will pause the execution to finish the callback (after the await) anytime.
}

将异步方法视为两部分方法。首先是逻辑和回调(等待语句之后的代码)。

希望这不是太难理解,如果需要,我可以澄清或重新表述。

【讨论】:

    【解决方案2】:

    异步回调是异步操作完成时将调用的回调。它通常作为参数传递给名称以 begin 开头的方法。或者您使用委托并执行 begininvoke

    整个过程微软在这里详细解释:https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx

    在我提供的链接中查找最后一个示例。

    【讨论】:

    • sampleFunction 完成后不会调用 test 吗?
    • 当然不是,如果你有一个对该方法的委托,然后执行 begininvoke 然后传递回调,它将被调用。阅读我提供的链接中的最后一个示例,它完全符合您的要求。
    • 我明白了,那么应该由 sampleFunction 下载的字符串会发生什么?
    • 应该是测试方法的返回值。然后使用 endinvoke 得到结果。
    【解决方案3】:

    我几乎 100% 确定您已经完全破坏了在 sampleFunction1sampleFunction2 中使用的命名约定

    我确定你的意思。

    public class Foo
    {
        public void BeginSampleFunction(AsyncCallback callback, object x)
        {
             //download some content as a string
        }
    
        public string EndSampleFunction(IAsyncResult result)
        {
             //download some content as a string
        }
    }
    

    测试代码应该是

    public void Test()
    {
        AsyncCallback callback = a =>
        {
            string result = foo.EndSampleFunction(a);
            Console.WriteLine(result);
        }
        object state = null;
        foo.BeginSampleFunction(callback, state);
    }
    

    这种模式称为异步编程模型 (APM)。它已完全弃用,不应使用。今天我们使用任务异步编程(TAP)。

    在 TPL 中有一个工厂方法可以将方法从 APM 转换为 TAP。

    public async Task Test()
    {
        Task<string> task = Task.Factory.FromAsync(foo.BeginSampleFunction, foo.EndSampleFunction, null);
        string result = await task;
        Console.WriteLine(result);
    }
    

    【讨论】:

    • 对此很抱歉.. 对此非常陌生。感谢修复
    • 在哪里调用回调?如果您执行 foo.BeginSampleFunction ,则您将参数传递给一个什么都不做的函数。没有人打电话给回调。这行不通。您需要一个委托并在委托上开始调用。
    • @PhilipStuyck 将回调传递给BeginXXX 方法的要点是,当它完成时,它将调用回调。没有代表可以调用BeginInvoke。这不是线程。这是异步 I/O。
    • @SKLAK 我已经编辑向您展示了使用基于 APM 的方法的更现代的方法,这些方法已被弃用。但是,如果该类还包含 SampleMethodTaskAsync,请改用它。
    • 重点是你的答案是错误的。 Beginblabla 应该在后台线程上做一些事情,并在完成时调用回调。使用您的代码没有后台线程。而且您必须自己调用回调。看看我提供的链接,它显示了正确的方法。
    猜你喜欢
    • 2012-08-24
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 2012-04-28
    相关资源
    最近更新 更多