C#中StreamReader直接调用与搭配using语句使用有何区别?生产环境该用哪种?
问题一:两种写法的区别
核心差异是非托管资源的释放逻辑完全不同:
- 第一种无using的写法
你创建的StreamReader实例在执行完ReadToEndAsync之后,不会被主动释放资源,只能等待.NET垃圾回收器(GC)在后续不定时的回收过程中才会清理它持有的缓冲区、流引用等非托管资源。如果读取过程中抛出异常,这个实例的资源甚至可能一直被占用,高并发场景下会快速堆积资源泄漏,最终导致服务器内存、句柄耗尽。
另外这种写法下,你完全无法控制StreamReader对底层context.Request.Body的处理行为,很容易出现后续逻辑无法读取请求流的问题。 - 第二种搭配using的写法
using是C#的语法糖,只要代码执行离开using的作用域(哪怕是读取过程中抛出异常提前退出),都会自动调用StreamReader的Dispose方法,主动、即时释放所有占用的非托管资源,完全避免了资源泄漏的风险。
问题二:给出的using写法是否可以在生产环境使用
分两种场景判断:
- 如果你的业务逻辑里,读取完请求JSON之后,后续所有流程(包括框架内置逻辑、其他中间件)都不会再读取
context.Request.Body:这个写法是符合规范的,可以用在生产环境,比第一种写法稳定很多。 - 如果后续还有其他逻辑需要读取
context.Request.Body:这个写法会有坑。因为StreamReader默认构造的情况下,Dispose时会自动关闭底层的请求流,后续再读取流会抛出「流已关闭」的异常。这种场景下需要修改构造参数,添加leaveOpen: true配置,示例如下:
string json; // leaveOpen设为true表示Dispose StreamReader时不关闭底层的Request.Body流 using (var reader = new StreamReader(context.Request.Body, leaveOpen: true)) { json = await reader.ReadToEndAsync(); }
额外建议:如果要多次读取context.Request.Body,最好先调用context.Request.EnableBuffering()开启请求流缓冲,避免流只能读取一次的问题
内容的提问来源于stack exchange,提问作者AndyP
相关产品推荐
相关产品推荐

