使用 async/await - C#

using async/await - c#

我有以下代码。这段代码究竟做了什么?为什么我们需要 StopwatchXmlSerializerMemoryStream。使用 async/await 是否有更简单的方法? 使用 contentResponse.Result; 也总是会导致死锁情况。

    public T GetResponse<T>()
    {
        var response = default(T);

            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);

                Stopwatch watch = Stopwatch.StartNew();

                var contentResponse = httpClient.GetAsync(uri.ToString());

                try
                {
                    contentResponse.Wait();
                }
                catch (Exception exception)
                {

                }

                var wsResponseContent = contentResponse.Result;
                wsResponseContent.Content.LoadIntoBufferAsync();
                var resultTask = wsResponseContent.Content.ReadAsStringAsync();
                resultTask.Wait();

                string wsResponseContentText = resultTask.Result;

                if (watch.IsRunning)
                    watch.Stop();

                wsResponseContent.EnsureSuccessStatusCode();
                if (wsResponseContent.IsSuccessStatusCode)
                {
                    XmlSerializer result = new XmlSerializer(typeof(T));

                    using (MemoryStream sresultStream = new MemoryStream(Encoding.UTF8.GetBytes(wsResponseContentText)))
                    {
                        response = (T)result.Deserialize(sresultStream);
                        sresultStream.Close();
                    }
                }
            }
       
        return response;
    }

此代码中不需要秒表。通常用作诊断工具,它可能很有用。但不是在这种情况下。 从下面的代码看来,它似乎读取了通过网络发送的字符串并尝试将其读取为 XML 格式。因此需要 MemoryStreamXMLSerializer.

至于你的死锁情况。总是因为两个实例试图访问同一个实例。您可以通过适当地等待您的功能来避免这种情况。 如果oyu真的想要一个合适的async实现函数如下:

public async Task<T> GetResponse<T>()
{
    var response = default(T);

    using (HttpClient httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);

        var contentResponse = await httpClient.GetAsync(uri.ToString());

        await wsResponseContent.Content.LoadIntoBufferAsync();
        var wsResponseContentText = await wsResponseContent.Content.ReadAsStringAsync();

        wsResponseContent.EnsureSuccessStatusCode();
        
        if (wsResponseContent.IsSuccessStatusCode)
        {
            XmlSerializer result = new XmlSerializer(typeof(T));

            using (MemoryStream sresultStream = new MemoryStream(Encoding.UTF8.GetBytes(wsResponseContentText)))
            {
                response = (T)result.Deserialize(sresultStream);
                sresultStream.Close();
             }
        }
    }
   
    return response;
}

在上面的代码中,如果函数中有 async。我们可以等待结果而不是任务。例如在下面的代码中:

public async Task<int> GetNumber5Async() {
    return 5;
}

如果我们像你以前那样称呼它:

var number5 = GetNumber5Async(); // Returns Task<int>

我们将收到一个我们需要从中获取结果的任务。但是,如果我们立即等待任务:

var number5 = await GetNumber5Async(); // Returns 5

我们会立即返回结果,而无需执行 number5.Wait(); number5.result;


一路乌龟下来

使用异步方法时,您需要了解的一件事是 'Turtes all the way Down' 的概念。 简单地说,如果你在任何地方都有一个异步方法,你所有的方法都会调用它,并且调用这些方法也需要是异步的。 那么异步方法需要什么?

  1. In 要求是 Task。因此,它需要 return 一个封装了值的 Task,而不是 returning 一个值。

例如:

// None Async
public int GetNumber5() { return 5;} 

// Async
public async Task<int> GetNumber5Async() { return 5; }
  1. 需要 async 描述符才能使用和调用 o 能够 await 函数。

例如:

// None Async
void GetANumber(){
    var num5 = GetNumber5();
}

// Async
async void GetANumber(){
    var num5 = await GetNumber5Async();
}

使用异步避免死锁

通常等待一个函数就够了。但是,如果它仍然会造成死锁,您可以添加 '.ConfigureAwait(false);'

例如:

var num5 = await GetNumber5Async().ConfigureAwait(false);