StreamReader 与 using 语句的区别?

StreamReader with using statement difference?

我在我的代码中使用 StreamReader,如下所示:

string json = await new StreamReader(context.Request.Body).ReadToEndAsync();
// ... use json variable here in some other code

我偶然发现了 using 语句。我的第一个语句与使用 using 语句和 StreamReader 之间有什么区别吗?

我应该在产品代码中使用带有 StreamReaderusing 语句吗?

        string json;
        using (var reader = new StreamReader(context.Request.Body))
        {
            json = await reader.ReadToEndAsync();
        }

看看这个link

https://www.c-sharpcorner.com/UploadFile/manas1/usage-and-importance-of-using-in-C-Sharp472/

简而言之:“using”语句确保 managed/unmanaged 资源对象正确处理,即使在 using 块中发生任何异常,您也不必显式调用“Dispose”方法

您也可以从微软官方网站进一步阅读

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#:~:text=The%20using%20statement%20calls%20the,t%20be%20modified%20or%20reassigned.

Is there any difference between my first statement vs using the using statement with StreamReader

是的。 不同之处在于,当您将 StreamReader 包装在 using statement it will clear up some resources directly instead of waiting for the garbage collector. More specifically it will call Dispose() on StreamReader. You should almost always use using when the class implements IDisposable.

中时

If your app simply uses an object that implements the IDisposable interface, you should call the object's IDisposable.Dispose implementation when you are finished using it.

感谢 .NET Core 是开源的,我们可以看看 the source for StreamReader:

protected override void Dispose(bool disposing)
{
    if (m_stream != null)
    {
        if (disposing)
        {
            m_stream.Close();
        }

        m_stream = null;
        m_buffer = null;
        m_curBufPos = 0;
        m_curBufLen = 0;
    }

    m_disposed = true;
}

如您所见,它会在流上调用 Close(),而后者 (according to the docs) 又会在流本身上调用 Dispose()

正确处理对象可以在处理较大的对象或流时至关重要。但是,我会尝试针对您的其他问题。

Should I be using using statement with StreamReader here in prod code?

是的,不是,也许。 在你的特殊情况下,你有一个 context.Request.Body 作为 Stream (我假设来自 HttpContext). StreamReader 不需要关闭那个 特定的 流。无论如何,它将被正确(稍后)处理。此外,可能还有一些其他资源需要稍后在管道中访问该特定流。

通常,如果 class 实现了 IDisposable,那么您应该将其包装在 using 中。但在这里我认为你有两个更好的选择:

1. 如果您实际上有一个 json (正如您的变量所建议的那样),您可以使用 System.Text.Json.JsonSerializer:

中的 JsonSerializer 直接反序列化它
YourModel model = await System.Text.Json.JsonSerializer.DeserializeAsync<YourModel>(context.Request.Body);

更新: 或者,如果您使用的是 .NET 5,则可以访问 HttpResponseJsonExtensions and can use ReadFromJsonAsync。那么您可以简单地尝试以下操作:

YourModel model = await context.Request.ReadFromJsonAsync<YourModel>();

感谢caius-jard

2. 使用不关闭流的overload of StreamReader

string json;
using (var reader = new StreamReader(stream, Encoding.UTF8, true, -1, true))
{
    json = await reader.ReadToEndAsync();
}

所以,总结一下。是的,使用 using 时会有所不同。但是,在您的特定情况下,您有更好的选择。