using

using是C# 語言中定義一個範圍,將在此範圍之外釋放一個或多個對象。

簡介

定義一個範圍,將在此範圍之外釋放一個或多個對象。

語法

using (Font font1 = new Font("Arial", 10.0f))

{

}

C# 語言參考

主要用途

using 關鍵字有兩個主要用途:

作為語句

用於定義一個範圍,在此範圍的末尾將釋放對象

using using

C# 通過 .NET Framework 公共語言運行庫 (CLR) 自動釋放用於存儲不再需要的對象的記憶體。記憶體的釋放具有不確定性;一旦 CLR 決定執行垃圾回收,就會釋放記憶體。但是,通常最好儘快釋放諸如檔案句柄和網路連線這樣的有限資源。

using 語句允許程式設計師指定使用資源的對象應當何時釋放資源。為 using 語句提供的對象必須實現 IDisposable 接口。此接口提供了 Dispose 方法,該方法將釋放此對象的資源。

可以在到達 using 語句的末尾時,或者在該語句結束之前引發了異常並且控制權離開語句塊時,退出 using 語句。

1. 可以在 using 語句中聲明對象(如上所示),或者在 using 語句之前聲明對象,如下所示:

示例1

下面的示例顯示用戶定義類可以如何實現它自己的 Dispose 行為。注意類型必須從 IDisposable 繼承。

作為指令

用於為命名空間創建別名或導入其他命名空間中定義的類型

①.允許在命名空間中使用類型,這樣,您就不必在該命名空間中限定某個類型的使用:

using System.Text;

②.為命名空間或類型創建別名。

using Project = PC.MyCompany.Project;

using 指令的範圍限制為包含它的檔案。

創建 using 別名,以便更易於將標識符限定到命名空間或類型。

創建 using 指令,以便在命名空間中使用類型而不必指定命名空間。 using 指令不為您提供對嵌套在指定命名空間中的任何命名空間的訪問。

命名空間分為兩類:用戶定義的命名空間和系統定義的命名空間。用戶定義的命名空間是在代碼中定義的命名空間。若要查看系統定義的命名空間的列表

示例2

1.下面的示例顯示了如何為命名空間定義和使用 using 別名:

輸出: You are in NameSpace1.MyClass

=========================================================================================

深入討論

引言

在.NET大家庭中,有不少的關鍵字承擔了多種角色,例如new關鍵字就身兼數職,除了能夠創建對象,在繼承體系中隱藏基類成員,還在泛型聲明中約束可能用作類型參數的參數,在詳細討論using的多重身份的基礎上來了解.NET在語言機制上的簡便與深邃。

那么,using的多重身份都體現在哪些方面呢,我們先一睹為快吧:

· 引入命名空間

· 創建別名

· 強制資源清理

下面,本文將從這幾個角度來闡述using的多彩套用。

引入命名空間

using作為引入命名空間指令的用法規則為:

using Namespace;

在.NET程式中,最常見的代碼莫過於在程式檔案的開頭引入System命名空間,其原因在於System命名空間中封裝了很多最基本最常用的操作,下面的代碼對我們來說最為熟悉不過:

using System;

這樣,我們在程式中就可以直接使用命名空間中的類型,而不必指定詳細的類型名稱。using指令可以訪問嵌套命名空間。

關於:命名空間

命名空間是.NET程式在邏輯上的組織結構,而並非實際的物理結構,是一種避免類名衝突的方法,用於將不同的數據類型組合劃分的方式。例如,在.NET中很多的基本類型都位於System命名空間,數據操作類型位於System.Data命名空間,

誤區

· using類似於Java語言的import指令,都是引入命名空間(Java中稱作包)這種邏輯結構;而不同於C語言中的#include指令,用於引入實際的類庫,

· using引入命名空間,並不等於編譯器編譯時載入該命名空間所在的程式集,程式集的載入決定於程式中對該程式集是否存在調用操作,如果代碼中不存在任何調用操作則編譯器將不會載入using引入命名空間所在程式集。因此,在源檔案開頭,引入多個命名空間,並非載入多個程式集,不會造成“過度引用”的弊端。 using為命名空間創建別名的用法規則為:

using alias = namespace | type;

其中namespace表示創建命名空間的別名;而type表示創建類型別名。例如,在.NET Office套用中,常常會引入Microsoft.Office.Interop.Word.dll程式集,在引入命名空間時為了避免繁瑣的類型輸入,我們通常為其創建別名如下:

using MSWord = Microsoft.Office.Interop.Word;

這樣,就可以在程式中以MSWord來代替Microsoft.Office.Interop.Word前綴,如果要創建Application對象,則可以是這樣,

private static MSWord.Application ooo = new MSWord.Application();

同樣,也可以創建類型的別名,用法為:

using using

而創建別名的另一個重要的原因在於同一cs檔案中引入的不同命名空間中包括了相同名稱的類型,為了避免出現名稱衝突可以通過設定別名來解決,例如: namespace Boyspace

{

public class Player

{

public static void Play()

{

System.Console.WriteLine("Boys play football.");

}

}

}

namespace Girlspace

{

public class Player

{

public static void Play()

{

System.Console.WriteLine("Girls play violin.");

}

}

}

以using創建別名,有效的解決了這種可能的命名衝突,儘管我們可以通過類型全名稱來加以區分,但是這顯然不是最佳的解決方案,using使得這一問題迎刃而解,不費絲毫功夫,同時在編碼規範上看來也更加的符合編碼要求。

強制資源清理

4.1 由來

要理解清楚使用using語句強制清理資源,就首先從了解Dispose模式說起,而要了解Dispose模式,則應首先了解.NET的垃圾回收機制。這些顯然不是本文所能完成的宏論,我們只需要首先明確的是.NET提供了Dispose模式來實現顯式釋放和關閉對象的能力。

Dispose模式

Dispose模式是.NET提供的一種顯式清理對象資源的約定方式,用於在.NET 中釋放對象封裝的非託管資源。因為非託管資源不受GC控制,對象必須調用自己的Dispose()方法來釋放,這就是所謂的Dispose模式。從概念角度來看,Dispose模式就是一種強制資源清理所要遵守的約定;從實現角度來看,Dispose模式就是讓要一個類型實現IDisposable接口,從而使得該類型提供一個公有的Dispose方法。

本文不再討論如何讓一個類型實現Dispose模式來提供顯示清理非託管資源的方式,而將注意集中在如何以using語句來簡便的套用這種實現了Dispose模式的類型的資源清理方式。我們在記憶體管理與垃圾回收章節將有詳細的討論。

using語句提供了強制清理對象資源的便捷操作方式,允許指定何時釋放對象的資源,其典型套用為:

using (Font f = new Font("Verdana", 12, FontStyle.Regular))

{

//執行文本繪製操作

Graphics g = e.Graphics;

Rectangle rect = new Rectangle(10, 10, 200, 200);

g.DrawString("Try finally dispose font.", f, Brushes.Black, rect);

}//運行結束,釋放f對象資源

在上述典型套用中,using語句在結束時會自動調用欲被清除對象的Dispose()方法。因此,該Font對象必須實現IDispose接口,才能使用using語句強制對象清理資源。我們查看其類型定義可知:

public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable

Font類型的確實現了IDisposeable接口,也就具有了顯示回收資源的能力。然而,我們並未從上述代碼中,看出任何使用Dispose方法的蛛絲馬跡,這正式using語句帶來的簡便之處,其實質究竟怎樣呢?

4.2 實質

要想了解using語句的執行本質,了解編譯器在背後做了哪些手腳,就必須回歸到IL代碼中來揭密才行:

.method public hidebysig static void Main() cil managed

{

.entrypoint

// 代碼大小 40 (0x28)

.maxstack 4

.locals init ([0] class [System.Drawing]System.Drawing.Font f,

[1] bool CS$4$0000)

IL_0000: nop

IL_0001: ldstr "Verdana"

IL_0006: ldc.r4 12.

IL_000b: ldc.i4.0

IL_000c: newobj instance void [System.Drawing]System.Drawing.Font::.ctor(string,float32,

valuetype [System.Drawing]System.Drawing.FontStyle)

IL_0011: stloc.0

.try

{

……部分省略……

} // end .try

finally

{

……部分省略……

IL_001f: callvirt instance void [mscorlib]System.IDisposable::Dispose()

IL_0024: nop

IL_0025: endfinally

} // end handler

IL_0026: nop

IL_0027: ret

} // end of method UsingDispose::Main

顯然,編譯器在自動將using生成為try-finally語句,並在finally塊中調用對象的Dispose方法,來清理資源。

在.NET規範中,微軟建議開放人員在調用一個類型的Dispose()或者Close()方法時,將其放在異常處理的finally塊中。根據上面的分析我們可知,using語句正是隱式的調用了類型的Dispose方法,因此以下的代碼和上面的示例是完全等效的:

Font f2 = new Font("Arial", 10, FontStyle.Bold);

try

{

//執行文本繪製操作

Graphics g = new Graphics();

Rectangle rect = new Rectangle(10, 10, 200, 200);

g.DrawString("Try finally dispose font.", f2, Brushes.Black, rect);

}

finally

{

if (f2 != null)

((IDisposable)f2).Dispose();

}

4.3 規則

· using只能用於實現了IDisposable接口的類型,禁止為不支持IDisposable接口的類型使用using語句,否則會出現編譯時錯誤;

· using語句適用於清理單個非託管資源的情況,而多個非託管對象的清理最好以try-finnaly來實現,因為嵌套的using語句可能存在隱藏的Bug。內層using塊引發異常時,將不能釋放外層using塊的對象資源。

· using語句支持初始化多個變數,但前提是這些變數的類型必須相同,例如:

using(Pen p1 = new Pen(Brushes.Black), p2 = new Pen(Brushes.Blue))

{

//

}

否則,編譯將不可通過。不過,還是有變通的辦法來解決這一問題,原因就是套用using語句的類型必然實現了IDisposable接口,那么就可以以下面的方式來完成初始化操作,

using (IDisposable font = new Font("Verdana", 12, FontStyle.Regular), pen = new Pen(Brushes.Black))

{

float size = (font as Font).Size;

Brush brush = (pen as Pen).Brush;

}

另一種辦法就是以使用try-finally來完成,不管初始化的對象類型是否一致。

· Dispose方法用於清理對象封裝的非託管資源,而不是釋放對象的記憶體,對象的記憶體依然由垃圾回收器控制。

· 程式在達到using語句末尾時退出using塊,而如果到達語句末尾之前引入異常則有可能提前退出。

· using中初始化的對象,可以在using語句之前聲明,例如:

Font f3 = new Font("Verdana", 9, FontStyle.Regular);

using (f3)

{

//執行文本繪製操作

}

結論

一個簡單的關鍵字,多種不同的套用場合。本文從比較全面的角度,詮釋了using關鍵字在.NET中的多種用法,值得指出的是這種用法並非實現於.NET的所有高級語言,本文的情況主要局限在C#中。

相關詞條

相關搜尋

熱門詞條

聯絡我們