使用哪个 WebClient.OpenRead、OpenReadAsync 或 OpenReadTaskAsync

Which to use, WebClient.OpenRead, OpenReadAsync or OpenReadTaskAsync

我正在尝试了解 WebClient.OpenRead, WebClient.OpenReadAsync and WebClient.OpenReadTaskAsync 之间的差异。

貌似在阻塞线程方面有区别,但我不是很了解
你能解释一下不同之处吗?如果你能给我一些例子就太好了(例子不一定是示例代码,但如果你能提供就更好了)

我建议 WebClient 现在或多或少已经过时了,HttpClient 更适合任何面向 .NET Framework 4.5+ 或 .NET Core 的应用程序。请注意后者不会自动抛出 HTTP 错误代码 (400+) 的异常。

如您所说,区别在于线程阻塞行为。第一个 (OpenRead()) 是线程阻塞操作,其他两个不是。例如,假设您达到 google.com 的网络延迟为 300 毫秒。当您执行 var stream = webClient.OpenRead(@"https://www.google.com"); 时,您的应用程序在这 300 毫秒内为 "paused",因此直到您的 webClient return 到 stream 变量的流。这是调用线程阻塞

当您在 UI 线程中执行此操作时(例如:在按钮单击处理程序中)- 您的应用程序变得冻结并且不响应用户操作。这是 糟糕的 用户体验,所以永远不要在 UI 中调用线程阻塞的东西。这是控制台应用程序的示例:

var address = @"https://www.google.com/";

Console.WriteLine($"Opening stream from {address}");
using (var stream = webClient.OpenRead(address)) // this will block for 300ms
{
    Console.WriteLine("Stream is open!");
    // some other code
}

第二种方法(OpenReadAsync()) is asynchronous and return nothing immediately after a call, so your thread is not blocked. After awhile (300ms) OpenReadCompleted 事件将由您的 webClient 引发,所有附加的侦听器将逐个处理打开的流。这是一个示例:

public partial class MainForm : Form
{
    private WebClient _client = new WebClient();

    public MainForm()
    {
        InitializeComponents();
        _client.OpenReadCompleted += OpenReadCompletedHandler;
    }

    private void ButtonClickHandler(object sender, EventArgs e)
    {
        _client.OpenReadAsync(@"https://www.google.com/");
    }

    private void OpenReadCompletedHandler(object sender, OpenReadCompletedEventArgs e)
    {
        // this event will be raiesed 300ms after 'Button' click
        var stream = e.Result; // <- here is your stream
        // some other code
    }
}

最后一个(OpenReadTaskAsync()) is all about TPL (Task Parallel Library)async/await 关键字。它在 Task 这是 return 通过这种方法编辑的。这是一个示例:

public partial class MainForm : Form
{
    private WebClient _client = new WebClient();

    public MainForm()
    {
        InitializeComponents();
    }

    private async void ButtonClickHandler(object sender, EventArgs e)
    {
        // after 'await' keyword, execution will be returned from this method immediately
        // meanwhile, actual acquiring of 'stream' is running in a background thread
        using (var stream = await _client.OpenReadTaskAsync(@"https://www.google.com/"))
        {
            // after 300ms, this code will be continued in UI thread
            // result will be automaticly unpacked to 'stream' variable

            // some other code
        }
    }
}

希望这对您有所帮助。