C# using 關(guān)鍵字用法以及容易踩的坑
很多 C# 初學(xué)者都知道 using? 關(guān)鍵字,但對(duì)它的兩個(gè)主要用途——指令和語句——經(jīng)?;煜?。這篇就來完整聊聊 using 的關(guān)鍵用法、經(jīng)典場景以及容易踩的坑。
- using 指令與語句的區(qū)別:搞清楚各自的作用與使用場景
- 常用操作詳解:文件、數(shù)據(jù)庫、自定義資源的管理
- C# 8.0 using 聲明:新語法的便利與潛在陷阱
- 與 try-finally 的關(guān)系:理解本質(zhì)原理,用好代碼簡化
- 靜態(tài)方法導(dǎo)入:用
using static提升代碼可讀性
一、概述
?using? 關(guān)鍵字在 C# 中有兩個(gè)主要用途:作為指令和作為語句。
- using 指令:用于引入命名空間,以便在代碼中直接使用該命名空間中的類型,而無需使用完全限定名。此外,還可以定義類型別名。
- using 語句:用于確保資源(如文件、數(shù)據(jù)庫連接)在使用后被正確釋放,通常用于實(shí)現(xiàn)
IDisposable接口的對(duì)象。
劃重點(diǎn): using 語句的本質(zhì)是 try-finally 的語法糖,保證資源一定會(huì)被釋放,無論正常執(zhí)行還是拋出異常。
二、使用場景
using 指令
- 當(dāng)需要頻繁使用某個(gè)命名空間中的類型時(shí),使用
using指令簡化代碼。 - 例如,使用
System.IO命名空間中的類來處理文件操作。
using 語句
- 當(dāng)需要確保資源(如文件、數(shù)據(jù)庫連接等)在使用后被正確釋放時(shí),使用
using語句。 - 例如,讀取文件時(shí),使用
using語句可以確保文件流在使用后被關(guān)閉。
三、注意事項(xiàng)
- 使用
using? 語句時(shí),確保對(duì)象實(shí)現(xiàn)了IDisposable接口。 - 不要在
using? 語句塊外部使用該語句中聲明的對(duì)象,因?yàn)樵搶?duì)象在using塊結(jié)束后會(huì)被釋放。
常見坑: 在 C# 8.0 的 using 聲明中,變量會(huì)在作用域結(jié)束時(shí)釋放,如果后續(xù)代碼還想訪問該變量,就會(huì)導(dǎo)致 ObjectDisposedException。
四、基本用法
4.1 using 指令
using System;
using System.IO;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
File.WriteAllText("example.txt", "This is a test file.");
}
}4.2 using 語句
using (var file = new StreamWriter("example.txt"))
{
file.WriteLine("This is a test file.");
}
// 文件流在此處自動(dòng)關(guān)閉五、常用操作
5.1 讀取文件
using (var file = new StreamReader("example.txt"))
{
string content = file.ReadToEnd();
Console.WriteLine(content);
}
// 文件流在此處自動(dòng)關(guān)閉5.2 處理數(shù)據(jù)庫連接
using (var connection = new SqlConnection("connection_string"))
{
connection.Open();
// 執(zhí)行數(shù)據(jù)庫操作
}
// 數(shù)據(jù)庫連接在此處自動(dòng)關(guān)閉5.3 多個(gè) using 語句
using (var file1 = new StreamReader("file1.txt"))
using (var file2 = new StreamWriter("file2.txt"))
{
string content = file1.ReadToEnd();
file2.Write(content);
}
// 兩個(gè)文件流在此處自動(dòng)關(guān)閉代碼解析:
- 嵌套 using:C# 允許連續(xù)多個(gè)
using? 而不需要花括號(hào)嵌套,每個(gè)using都會(huì)在作用域結(jié)束時(shí)依次釋放資源。 - 釋放順序:后聲明的先釋放(相當(dāng)于棧結(jié)構(gòu)),
file2? 先釋放,file1后釋放。
5.4 自定義 IDisposable 實(shí)現(xiàn)
public class CustomResource : IDisposable
{
public void Dispose()
{
// 釋放資源
Console.WriteLine("Resource disposed.");
}
}
using (var resource = new CustomResource())
{
// 使用資源
}
// 資源在此處自動(dòng)釋放5.5 使用 using 定義別名
?using 關(guān)鍵字還可以用于定義類型別名,以便在代碼中使用更簡潔的名稱。
// 定義一個(gè)命名空間
namespace MyNamespace
{
public class MyClass
{
public void MyMethod()
{
Console.WriteLine("Hello from MyClass in MyNamespace!");
}
}
}
// 定義類型別名
using MyAlias = MyNamespace.MyClass;
class Program
{
static void Main()
{
// 使用類型別名
MyAlias myAlias = new MyAlias();
myAlias.MyMethod(); // 輸出 "Hello from MyClass in MyNamespace!"
}
}提示: 類型別名多用于處理同名類沖突或縮短超長類型名,不適合濫用,否則反而降低可讀性。
5.6 使用擴(kuò)展方法簡化資源管理
public static class DisposableExtensions
{
public static void Use<T>(this T resource, Action<T> action) where T : IDisposable
{
using (resource)
{
action(resource);
}
}
}
// 使用擴(kuò)展方法
new StreamReader("example.txt").Use(file =>
{
string content = file.ReadToEnd();
Console.WriteLine(content);
});
// 文件流在此處自動(dòng)關(guān)閉六、定義資源管理塊
在 .NET 中,內(nèi)存管理主要依賴于垃圾回收機(jī)制(GC),但某些資源(如文件、數(shù)據(jù)庫連接等)需要顯式釋放。using 關(guān)鍵字提供了一種簡潔的方式來管理這些資源。
6.1 垃圾回收(GC)與確定性資源釋放(DRD)
- 垃圾回收(GC) :自動(dòng)管理內(nèi)存,釋放不再使用的對(duì)象。
- 確定性資源釋放(DRD) :通過
IDisposable? 接口和using語句手動(dòng)釋放非托管資源。
6.2 使用 IDisposable 接口和 using 語句
string connStr = "Data Source=.;Initial Catalog=demo1;Integrated Security=True";
using (var conn = new SqlConnection(connStr))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from T_Articles";
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// 處理數(shù)據(jù)
}
}
}
}代碼解析:
- 遞歸 using:
SqlConnection? →SqlCommand? →SqlDataReader,層層嵌套,每個(gè)資源都確保釋放。 - 釋放順序:里層先釋放(
reader? →cmd? →conn),與資源依賴順序一致。
6.3 C# 8.0 的 using 聲明
C# 8.0 引入了 using 聲明,簡化了資源管理代碼。資源在作用域結(jié)束時(shí)自動(dòng)釋放。
public class MyFile : IDisposable
{
public void Dispose()
{
Console.WriteLine("MyFile被釋放了");
}
}
static void TestDispose()
{
using MyFile myfile = new MyFile();
Console.WriteLine("TestDispose執(zhí)行完畢");
}6.4 using 聲明的陷阱及解決方案
?using 聲明可能導(dǎo)致資源在訪問前被釋放。以下是兩個(gè)解決方案:
方案一:使用傳統(tǒng)using語句
using (var outStream = File.OpenWrite("e:/1.txt"))
using (var writer = new StreamWriter(outStream))
{
writer.WriteLine("hello");
}
string s = File.ReadAllText("e:/1.txt");方案二:為using聲明添加額外的作用域
{
using var outStream = File.OpenWrite("e:/1.txt");
using var writer = new StreamWriter(outStream);
writer.WriteLine("hello");
}
string s = File.ReadAllText("e:/1.txt");本案例的執(zhí)行流程(拆解版):
- 外層作用域:進(jìn)入花括號(hào)塊,聲明
outStream? 和writer,開始寫文件。 - 離開作用域:花括號(hào)結(jié)束后,
writer? 先釋放(關(guān)閉文件流并寫入緩沖區(qū)),然后outStream釋放。 - 成功讀取:此時(shí)文件已完全關(guān)閉,后續(xù)
ReadAllText可以正常讀取。
劃重點(diǎn): using 聲明的作用域是它所在的塊(方法體、循環(huán)體或花括號(hào)塊),而不像 using 語句有顯式的大括號(hào)邊界。一定要確保在資源釋放前完成所有使用操作。
七、using 語句與 try-finally 的等效性
?using? 語句是 try-finally 結(jié)構(gòu)的語法糖,確保資源在使用完畢后被釋放。
傳統(tǒng) try-finally 寫法
StreamWriter sw = null;
try
{
sw = new StreamWriter("d:\\abc.txt");
sw.WriteLine("test");
}
finally
{
if (sw != null)
{
sw.Dispose();
}
}使用 using 語句簡化
using (var sw = new StreamWriter("d:\\abc.txt"))
{
sw.WriteLine("test");
}?using? 語句創(chuàng)建作用域,控制流離開作用域時(shí),無論正常執(zhí)行還是異常,自動(dòng)調(diào)用 sw? 的 Dispose 方法。簡化代碼,確保資源正確釋放。
劃重點(diǎn): 編譯器會(huì)將 using 語句編譯為 try-finally 塊,這是確定性的資源釋放機(jī)制,與 GC 的非確定性內(nèi)存回收不同。
八、靜態(tài)方法導(dǎo)入
?using static 指令可以導(dǎo)入類的靜態(tài)成員,簡化代碼,提高可讀性。
8.1 導(dǎo)入單個(gè)類的靜態(tài)方法
using static System.Math;
導(dǎo)入 System.Math 類的所有靜態(tài)方法,直接使用這些方法:
double result = Sqrt(16); // 直接使用 Math.Sqrt
8.2 導(dǎo)入具有靜態(tài)和實(shí)例方法的類的靜態(tài)方法
using static System.String;
導(dǎo)入 System.String? 類的靜態(tài)方法,直接使用 IsNullOrEmpty 方法:
bool isEmpty = IsNullOrEmpty(someString); // 直接使用 String.IsNullOrEmpty
8.3 在 LINQ 查詢中導(dǎo)入靜態(tài)方法
using static System.Linq.Enumerable;
導(dǎo)入 System.Linq.Enumerable?,在 LINQ 查詢中直接使用其靜態(tài)方法,如 Where?、Select 等:
var query = Range(0, 10).Select(x => x * x); // 直接使用 Enumerable.Range 和 Select
注意: using static 雖然能減少代碼量,但過度使用可能導(dǎo)致命名沖突,降低可讀性。建議只在同一個(gè)類的方法被頻繁調(diào)用時(shí)使用。
最后
?using? 關(guān)鍵字是 C# 中資源管理的基石,從指令到語句再到聲明,每一次改進(jìn)都在簡化代碼的同時(shí)強(qiáng)化了確定性釋放。記?。?strong>能用 using 的地方就別手寫 try-finally,但也要警惕 C# 8.0 聲明的陷阱。寫出規(guī)范、可維護(hù)的代碼,從用好 using 開始。
到此這篇關(guān)于C# using 關(guān)鍵字用法以及容易踩的坑的文章就介紹到這了,更多相關(guān)C# using 關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#使用WebClient登錄網(wǎng)站并抓取登錄后的網(wǎng)頁信息實(shí)現(xiàn)方法
這篇文章主要介紹了C#使用WebClient登錄網(wǎng)站并抓取登錄后的網(wǎng)頁信息實(shí)現(xiàn)方法,涉及C#基于會(huì)話操作登陸網(wǎng)頁及頁面讀取相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
Unity實(shí)現(xiàn)倒計(jì)時(shí)組件
這篇文章主要介紹了Unity實(shí)現(xiàn)倒計(jì)時(shí)組件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
C#使用SQLite進(jìn)行大數(shù)據(jù)量高效處理的代碼示例
在軟件開發(fā)中,高效處理大數(shù)據(jù)量是一個(gè)常見且具有挑戰(zhàn)性的任務(wù),SQLite因其零配置、嵌入式、跨平臺(tái)的特性,成為許多開發(fā)者的首選數(shù)據(jù)庫,本文將深入探討如何使用SQLite優(yōu)化大數(shù)據(jù)量的存儲(chǔ)和檢索,,需要的朋友可以參考下2025-04-04
C#實(shí)現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法
這篇文章主要介紹了C#實(shí)現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法,涉及C#數(shù)組遍歷及隨機(jī)數(shù)操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08
C#/VB.NET實(shí)現(xiàn)創(chuàng)建PDF/UA文件的示例代碼
PDF/UA,即Universally?Accessible?PDF,該格式的PDF文件是于2012年8月以ISO標(biāo)準(zhǔn)14289-1發(fā)布的、具有普遍可訪問的PDF文檔標(biāo)準(zhǔn)。本文將用C#實(shí)現(xiàn)DF/UA文件的創(chuàng)建,需要的可以參考一下2022-08-08
WPF利用TabControl控件實(shí)現(xiàn)拖拽排序功能
在UI交互中,拖拽操作是一種非常簡單友好的交互,這篇文章主要為大家介紹了WPF如何利用TabControl控件實(shí)現(xiàn)拖拽排序功能,需要的小伙伴可以參考一下2023-10-10

