.net DownloadDataAsync+委托C在主函数中工作,但在类函数中不工作

.net DownloadDataAsync+委托C在主函数中工作,但在类函数中不工作,.net,webclient,.net,Webclient,我运行了个人密码。它作为一个主要的,但当我把它放在我的班上,它不工作。为什么? 它使bc data==null崩溃并引发null异常: public class Test2 { public void func() { byte[] data = null; WebClient client = new WebClient(); client.DownloadDataComplete

我运行了个人密码。它作为一个主要的,但当我把它放在我的班上,它不工作。为什么?

它使bc data==null崩溃并引发null异常:

public class Test2
    {
        public void func()
        {
            byte[] data = null;
            WebClient client = new WebClient();
            client.DownloadDataCompleted +=
                delegate(object sender, DownloadDataCompletedEventArgs e)
                {
                    data = e.Result;
                };
            Console.WriteLine("starting...");
            client.DownloadDataAsync(new Uri("https://stackoverflow.com/questions/"));
            while (client.IsBusy)
            {
                Console.WriteLine("\twaiting...");
                Thread.Sleep(100);
            }
            Console.WriteLine("done. {0} bytes received;", data.Length);
        }
    }

//i tried calling on form_load and a button click
new Test2().func();
对我有用吗

C:\TEMP\ConsoleApplication5\bin\Debug>ConsoleApplication5.exe
starting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
done. 48178 bytes received;
对我有用吗

C:\TEMP\ConsoleApplication5\bin\Debug>ConsoleApplication5.exe
starting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
done. 48178 bytes received;

如果在循环中等待结果,那么使用异步方法有什么意义?只需使用同步版本:

public class Test2
    {
        public void func()
        {
            WebClient client = new WebClient();
            byte[] data = client.DownloadData(new Uri("http://stackoverflow.com/questions/"));
            Console.WriteLine("done. {0} bytes received;", data.Length);
        }
    }

//i tried calling on form_load and a button click
new Test2().func();

如果在循环中等待结果,那么使用异步方法有什么意义?只需使用同步版本:

public class Test2
    {
        public void func()
        {
            WebClient client = new WebClient();
            byte[] data = client.DownloadData(new Uri("http://stackoverflow.com/questions/"));
            Console.WriteLine("done. {0} bytes received;", data.Length);
        }
    }

//i tried calling on form_load and a button click
new Test2().func();
此代码在数据字段上有一个字符。DownloadDataCompleted匿名委托是从与data.Length调用不同的线程调用的,在调用DownloadDataCompleted时,IsBusy变为false。这是两个线程之间关于谁首先访问数据的竞赛。如果主线程在下载线程上设置数据之前调用data.Length,则会出现空引用异常。必须很容易看出,您是否通过添加一个Thread.Sleep调用来强制DownloadDataCompleted delete始终取消竞争,然后再设置数据

线程的状态如下所示:

Main Thread             Download Thread     client.IsBusy
Waiting....             downloading...      true
leaves waiting loop     calls delegate      false
calls data.Length       data = e.Result
无法知道哪个线程将首先运行最后一行。在多处理器机器上,这两个都可以同时运行

因为这一切都是基于时间的,所以有时它会起作用,有时它会失败。您需要对多线程访问的所有数据进行某种同步锁定。

此代码在数据字段上有一个。DownloadDataCompleted匿名委托是从与data.Length调用不同的线程调用的,在调用DownloadDataCompleted时,IsBusy变为false。这是两个线程之间关于谁首先访问数据的竞赛。如果主线程在下载线程上设置数据之前调用data.Length,则会出现空引用异常。必须很容易看出,您是否通过添加一个Thread.Sleep调用来强制DownloadDataCompleted delete始终取消竞争,然后再设置数据

线程的状态如下所示:

Main Thread             Download Thread     client.IsBusy
Waiting....             downloading...      true
leaves waiting loop     calls delegate      false
calls data.Length       data = e.Result
无法知道哪个线程将首先运行最后一行。在多处理器机器上,这两个都可以同时运行


因为这一切都是基于时间的,所以有时它会起作用,有时它会失败。您需要对多线程访问的所有数据进行某种同步锁定。

由于shf301指出的winform线程模型,我修改了适用于我的代码

private void button1_Click(object sender, EventArgs e)
{
    func();
}
void func()
{
    WebClient client = new WebClient();
    byte[] data = null;
    long rcv = 0; //last number of bytes received

    //check data received for progress
    client.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
    {
        if (e.BytesReceived - rcv > 1000)
        {
            Console.WriteLine("\tBytes Received: " + e.BytesReceived.ToString());
            rcv = e.BytesReceived;
        }
        //else don't report
        Thread.Sleep(1);
    };
    client.DownloadDataCompleted +=
        delegate(object sender, DownloadDataCompletedEventArgs e)
        {
            data = e.Result;
            Console.WriteLine("done. {0} bytes received;", data.Length);
        };
    Console.WriteLine("starting...");

    //fire and forget
    client.DownloadDataAsync(new Uri("http://stackoverflow.com/questions/"));
}
结果如下:

starting...
    Bytes Received: 8192
    Bytes Received: 11944
    Bytes Received: 15696
    Bytes Received: 20136
    Bytes Received: 24232
    Bytes Received: 28040
    Bytes Received: 32424
    Bytes Received: 36176
    Bytes Received: 40616
    Bytes Received: 44712
    Bytes Received: 48269
done. 48269 bytes received;

由于shf301指出的winform线程模型,我修改了适合我的代码

private void button1_Click(object sender, EventArgs e)
{
    func();
}
void func()
{
    WebClient client = new WebClient();
    byte[] data = null;
    long rcv = 0; //last number of bytes received

    //check data received for progress
    client.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
    {
        if (e.BytesReceived - rcv > 1000)
        {
            Console.WriteLine("\tBytes Received: " + e.BytesReceived.ToString());
            rcv = e.BytesReceived;
        }
        //else don't report
        Thread.Sleep(1);
    };
    client.DownloadDataCompleted +=
        delegate(object sender, DownloadDataCompletedEventArgs e)
        {
            data = e.Result;
            Console.WriteLine("done. {0} bytes received;", data.Length);
        };
    Console.WriteLine("starting...");

    //fire and forget
    client.DownloadDataAsync(new Uri("http://stackoverflow.com/questions/"));
}
结果如下:

starting...
    Bytes Received: 8192
    Bytes Received: 11944
    Bytes Received: 15696
    Bytes Received: 20136
    Bytes Received: 24232
    Bytes Received: 28040
    Bytes Received: 32424
    Bytes Received: 36176
    Bytes Received: 40616
    Bytes Received: 44712
    Bytes Received: 48269
done. 48269 bytes received;


func不是虚拟函数。异常是在带有“data.Length”的行中引发的,是吗?糟糕,它最初位于虚拟func中。我的考试是在普通班。是,在data.length处,数据为nullfunc不是虚拟函数。异常是在带有“data.length”的行中引发的,是吗?噢,原来它是在虚拟函数中。我的考试是在普通班。是的,在data.length中,数据为空,但代码保持不变。这是一次考试,但在一堂课上失败了。我现在不知道为什么。同步版本会停止GUI线程。挂起正在使用它的任何应用程序。@Wolf5,使用异步版本并同步等待它完成,这就是OP正在做的,具有完全相同的效果。。。重新阅读原始代码你是对的。虽然如果他在等待循环中使用DoEvents,GUI线程在等待时不会锁定,但如果窗口是winforms,他可以移动窗口等。不确定这是否适用于同步版本。重点是保持代码不变。这是一次考试,但在一堂课上失败了。我现在不知道为什么。同步版本会停止GUI线程。挂起正在使用它的任何应用程序。@Wolf5,使用异步版本并同步等待它完成,这就是OP正在做的,具有完全相同的效果。。。重新阅读原始代码你是对的。虽然如果他在等待循环中使用DoEvents,GUI线程在等待时不会锁定,但如果窗口是winforms,他可以移动窗口等。不确定这是否适用于synch version.Perfect。我想一想,这其实很合乎逻辑。但我不知道为什么它能在控制台应用程序上工作。测试代码确实有效,我将继续。谢谢:@acidzombie24:您从中复制的代码是控制台应用程序的代码,它运行该过程并退出。因此,在下载完成之前,作者必须引入某种形式的机制来“阻止”应用程序不正常退出。对于Windows窗体,窗体模型允许您运行异步操作,而无需担心应用程序退出,因此不需要“暂停”技巧。在Winform.Perfect中可以看到我在本页答案中的代码。我想一想,这其实很合乎逻辑。但我不知道为什么它能在控制台应用程序上工作。测试代码确实有效,我将继续。谢谢:@acidzombie24:您从中复制的代码是用于 一个控制台应用程序,它运行程序并退出。因此,在下载完成之前,作者必须引入某种形式的机制来“阻止”应用程序不正常退出。对于Windows窗体,窗体模型允许您运行异步操作,而无需担心应用程序退出,因此不需要“暂停”技巧。请参阅我在Winform中工作的本页答案中的代码。