聊聊 C# 中 using 语句可能的 3 个陷阱

embedded/2024/9/19 0:36:48/ 标签: c#, using, 程序陷阱, 基础知识

image

前言

大家都知道,C# 中可以用 using 关键字来简化非托管资源(如文件流、数据库连接等)的释放,当变量离开 using 作用的范围后,会自动调用对象的 Dispose 方法,从而完成非托管资源的释放。在 C#8.0,进一步引入了简化版的 “using声明” 语法来避免多个 using 语句的嵌套,保证代码的优美,例如:

c#">string connStr = "......";using var conn = new SqlConnection(connStr);conn.Open();using var cmd = conn.CreateCommand();cmd.CommandText = "select * from testdb";using var reader = cmd.ExecuteReader();while (reader.Read())
{// ......
}

虽然 using 语句非常有用,但在实际使用过程中也存在一些潜在的问题,不可不察!

可能的陷阱

  1. 嵌套使用 using 语句

    当多个 using 语句嵌套在一起,内部 using 语句中的资源在释放时,可能会把外部 using 语句中的资源也释放掉,比如:

    c#">using (Stream stream = new FileStream("d:\1.txt", FileMode.OpenOrCreate))
    {using (StreamWriter writer = new StreamWriter(stream)){// ......}
    }
    

    例子中当内部的 writer 释放时,会同时释放外部的 stream 对象,这是因为 StreamWriter 类型 Dispose 机制所造成,所以当我们不太清除内层对象是否与外层对象有关系时,尤其要慎用 using 语句。

    除此之外,外部的 using 有时候也可能会在内部的 using 结束前就释放资源,导致意外的问题发生,比如数据库连接。

  2. 资源释放顺序:

    当多个 using 语句嵌套在一起时,如果多个资源需要按照特定顺序释放时,using 语句可能无法保证这一顺序,导致意外的问题发生。

  3. 作用域:

    简化版的 “using声明” 语法默认的作用域是整个方法体,所以很容易导致意外的问题发生,比如以下代码:

    c#">void usingTest() 
    {using var outStream = File.OpenWrite("d:/1.txt");using var writer = new StreamWriter(outStream);writer.WriteLine("Hello world");string s = File.ReadAllText("d:/1.txt");Console.WriteLine(s);
    }
    

    当代码执行到下面这行代码时,就会提示文件被占用的错误。

    c#">string s = File.ReadAllText("d:/1.txt");
    

    需要记得用花括号 {}using 语句包起来才能避免这个问题,如:

    c#">void usingTest() 
    {{using var outStream = File.OpenWrite("d:/1.txt");using var writer = new StreamWriter(outStream);writer.WriteLine("Hello world");}string s = File.ReadAllText("d:/1.txt");Console.WriteLine(s);
    }
    

总结

using 语句本质上是 try-finally 的语法糖,所以当多个 using 语句嵌套在一起的时候,实际上就是多个 try-finally 语句嵌套在一起,所以造成一些奇怪的问题也就不奇怪了,尤其是 C#8.0 进一步简化 using 语句之后。

我们在享受 using 语句带来的便利的同时,也要注意 using 语句正确的使用场景,尤其是在需要使用嵌套 using 语句的时候,这样才能提高程序的健壮性。

最后,using 语句除了用于释放非托管资源之外,还在其它的用途,比如引用命名空间、为命名空间或类型创建别名等,有兴趣的童鞋可以继续深入了解。

我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得。欢迎关注老杨的公众号,相互交流,共同进步!


http://www.ppmy.cn/embedded/96172.html

相关文章

使用旧笔记本电脑搭建私人NAS

使用旧笔记本电脑来搭建一个私人网络附加存储(NAS),不仅可以充分利用旧硬件,还能为你的家庭或小型办公室提供文件共享、备份和媒体流等功能。 市面上性能好点的NAS设备,在2000左右,太贵了,感兴…

基于 springboot 2 和 vue 3 的 博客论坛系统

1. 网站信息 博客论坛系统:http://106.53.164.141:8200 本网站是 基于 SpringBootVue 前后端分离的博客论坛系统 前台用户:注册登录;博客和活动相关的展示、浏览、点赞、收藏、评论、编辑等功能 后台管理员:管理公告、博客、活…

前端css线性渐变

background: linear-gradient(90deg,red,green); 1.支持多颜色渐变 2.支持多方向渐变 to left to top left 3.支持角度90deg <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA…

报名表EXCEL图片批量下载源码-CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构

每次报名表都会包含大量照片&#xff0c;一张一张下载很慢 可以通过未来之窗开源平台架构 开开excel批量下载 实现代码也很简单 function 未来之窗下载(){ let 未来之窗地址 document.getElementById("batchurl").value; let 保存路径 document.getElementById(…

Segment Routing MPLS介绍

定义 段路由SR&#xff08;Segment Routing&#xff09;是基于源路由理念而设计的在网络上转发数据包的一种协议。Segment Routing MPLS是指基于MPLS转发平面的Segment Routing&#xff0c;下文简称为Segment Routing。Segment Routing将网络路径分成一个个段&#xff0c;并且…

如何用JavaScript获取网页文档高度?

在日常开发中&#xff0c;我们经常需要在用户浏览页面时进行一些动态操作&#xff0c;比如实现无限滚动加载更多内容、调整布局、或触发动画效果。为了实现这些功能&#xff0c;准确获取整个网页文档的高度是关键的一步。今天&#xff0c;我们就结合一个实际业务场景&#xff0…

奥运会期间网络安全防护的重要性

北京时间凌晨3点&#xff0c;历史17天的巴黎奥运会迎来落幕&#xff0c;在此先祝贺伟大的祖国获得了总奖牌榜第二&#xff0c;金牌榜并列第一的好成绩&#xff0c;对征战在奥运会赛场的运动健儿们致敬&#xff01; 奥运会&#xff0c;作为全球规模最大、影响力最广的体育盛事&…

基于Spring Boot的可盈保险合同管理系统的设计与实现

TOC springboot146基于Spring Boot的可盈保险合同管理系统的设计与实现 绪论** 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关…

YII2的errorHandler.errorAction失效原因

<?phpreturn [components > [errorHandler > [errorAction > site/error,],] ]; 这段配置存在错误&#xff0c;导致错误处理无法生效。为了解决这个问题&#xff0c;我们需要对配置进行优化。 代码查看&#xff1a;yii\web\ErrorHandler::renderException <…

day6 测试基础知识积累

JMeter 服务端系统性能测试是针对服务器端应用程序或服务 在特定负载下的运行能力和稳定性进行评估的方法。 产品文档应该有产品的性能指标&#xff0c;做性能测试前&#xff0c;如果需求文档没有性能指标则要向产品团队要。服务端系统性能测试 的常见指标有&#xff1a;TPS、…

day36【LeetCode力扣】28.找出字符串中第一个匹配项的下标

day36【LeetCode力扣】28.找出字符串中第一个匹配项的下标 1.题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#x…

SpringWeb

SpringWeb SpringWeb 概述 SpringWeb 是 spring 框架中的一个模块&#xff0c;基于 Servlet API 构建的 web 框架. springWeb 是 Spring 为 web 层开发提供的一整套完备的解决方案。 在 web 层框架历经 Strust1&#xff0c;WebWork&#xff0c;Strust2 等诸多产品的历代更选之…

统计回归与Matlab软件实现上(一元多元线性回归模型)

引言 关于数学建模的基本方法 机理驱动 由于客观事物内部规律的复杂及人们认识程度的限制&#xff0c;无法得到内在因果关系&#xff0c;建立合乎机理规律的数学模型数据驱动 直接从数据出发&#xff0c;找到隐含在数据背后的最佳模型&#xff0c;是数学模型建立的另一大思路…

掌机系统MuOS游戏名称中文乱码解决主题

最近买了安伯尼克的rg35xxh掌机来玩儿&#xff0c;然后刷了muos&#xff0c;系统很小巧&#xff0c;1g的运行内存&#xff0c;系统运行的时候只占用了不到100m&#xff0c;而且界面也很美观&#xff0c;就是有一个问题——中文名称会乱码&#xff0c;都变成了方框&#xff0c;从…

PHP中如何限制PDF文件大小的简单示例

例如&#xff0c;如果我们希望限制PDF文件的大小不超过5MB&#xff0c;我们可以将这两个配置项都设置为5M。 upload_max_filesize 5M post_max_size 5M接下来&#xff0c;在PHP脚本中&#xff0c;我们可以通过检查$_FILES全局数组来获取上传文件的大小&#xff0c;并作出相应…

Docker修改容器名称

在Docker中&#xff0c;一旦容器被创建并运行&#xff0c;你不能直接修改容器的名称。容器的名称是在创建容器时通过docker run命令的--name选项指定的&#xff0c;或者在未指定名称时由Docker自动生成。如果你需要更改容器的名称&#xff0c;有几种方法可以间接实现这个目的&a…

浅析JavaScript 堆内存及其通过 Chrome DevTools 捕获堆快照的方法

JavaScript 的堆内存&#xff08;Heap Memory&#xff09;是内存中专门用于存放程序执行过程中动态生成的对象、函数实例以及其他动态数据结构的区域。与调用栈&#xff08;Call Stack&#xff09;专注于管理函数调用的顺序和执行环境不同&#xff0c;堆内存则专注于动态地分配…

ant -design 框架以及具体调试

1.介绍 Ant-Design-Vue 是一个基于 Ant Design 设计体系的 Vue 实现。Ant Design 是由阿里巴巴开源的一个企业级 UI 设计语言&#xff0c;旨在提升用户体验和开发效率。Ant-Design-Vue 将 Ant Design 的设计理念和组件库带入了 Vue 生态系统&#xff0c;使得开发者能够在 Vue …

Django:使用

新建一个本地输入 python3 pyshop/manage.py startapp products 会创建一个package 要把项目包改一下&#xff0c;移动成这样 ​​​​​​​ 输入 python3 manage.py runserver 先打开网址 修改/添加代码 views.py from django.http import HttpResponse from django.short…

深入解析依赖倒置原则

一、什么是依赖倒置原则 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是面向对象设计中的一项重要原则&#xff0c;其核心思想是高层模块不应该依赖于低层模块&#xff0c;二者都应该依赖于抽象&#xff1b;而抽象不应该依赖于细节&…