国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

ASP.NET技術(shù)FAQ

2019-11-18 19:50:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

1. 簡(jiǎn)介
1.1 什么是 .NET?
1.2 .NET 只是 Windows DNA 的一個(gè)新名字嗎?
1.3 .NET 只適用于建立 Web 網(wǎng)站嗎?
1.4 .NET 是在什么時(shí)候宣布的?
1.5 .NET 將在何時(shí)發(fā)布?
1.6 如何開(kāi)發(fā) .NET 應(yīng)用程序
1.7 可以從哪里下載 .NET SDK 和 Visual Studio 7?
1.8 .NET 中的關(guān)鍵技術(shù)是什么?
1.9 .NET 框架將運(yùn)行在什么平臺(tái)上?
1.10 .NET 框架支持什么語(yǔ)言?
1.11 .NET 框架符合標(biāo)準(zhǔn)化趨勢(shì)嗎?
 
2. 基本術(shù)語(yǔ)
2.1 什么是 CLR?
2.2 什么是 CTS?
2.3 什么是 CLS?
2.4 什么是 IL?
2.5 什么是 C#?
2.6 在 .NET 范疇里,“被管理”是什么含義?
2.7 什么是映像?
 
3. 元件
3.1 什么是元件?
3.2 怎樣創(chuàng)建元件?
3.3 私有元件和共享元件有什么不同?
3.4 元件如何相互找到?
3.5 元件版本如何起作用?
 
4. 應(yīng)用程序域
4.1 什么是應(yīng)用程序域?
4.2 如何創(chuàng)建 AppDomain?
4.3 我能編寫(xiě)自己的 .NET 宿主嗎?
 
5. 垃圾收集
5.1 什么是垃圾收集?
5.2 對(duì)對(duì)象的最后一個(gè)引用撤銷后,它并不一定立即被破壞,對(duì)嗎?
5.3 .NET 為什么不提供確定化的析構(gòu)?
5.4 在 .NET 中缺少確定化的析構(gòu)有問(wèn)題嗎?
5.5 確定化的析構(gòu)是否影響在被管理代碼中使用 COM 對(duì)象?
5.6 我聽(tīng)說(shuō)應(yīng)該避免使用 Finalize 方法,那么是否應(yīng)該在我的類里實(shí)現(xiàn) Finalize?
5.7 我有控制垃圾收集算法的手段嗎?
5.8 我怎么知道垃圾收集器在做什么?
 
6. 屬性
6.1 什么是屬性?
6.2 我能創(chuàng)建自己的 metadata 屬性嗎?
6.3 我能創(chuàng)建自己的 context 屬性嗎?
 
7. 代碼訪問(wèn)安全性
7.1 什么是代碼訪問(wèn)安全性 (CAS)?
7.2 CAS 如何起作用?
7.3 誰(shuí)定義 CAS 代碼組?
7.4 如何定義自己的代碼組?
7.5 如何改變代碼組的權(quán)限集?
7.6 能否創(chuàng)建自己的權(quán)限集?
7.7 CAS 有問(wèn)題時(shí),如何診斷自己的程序?
7.8 我受不了 CAS 帶來(lái)的麻煩,能否關(guān)掉它?
 
8. 中間語(yǔ)言 (IL)
8.1 我能看到元件的中間語(yǔ)言嗎?
8.2 能否通過(guò)反向工程從 IL 中獲得源代碼?
8.3 如何防止別人通過(guò)反向工程獲得我的代碼?
8.4 我能直接用 IL 編程嗎?
8.5 IL 能做到 C# 中做不到的事嗎?
 
9. 關(guān)于 COM
9.1 COM 消亡了嗎?
9.2 DCOM 消亡了嗎?
9.3 MTS/COM+ 消亡了嗎?
9.4 能在 .NET 中使用 COM 組件嗎?
9.5 能在 COM 中使用 .NET 組件嗎?
9.6 在 .NET 的世界中 ATL 是多余的嗎?
 
10. 雜項(xiàng)
10.1 .NET 的遠(yuǎn)程計(jì)算如何工作?
10.2 如何在 .NET 程序中獲得 Win32 API?
 
11. 類庫(kù)
11.1 文件 I/O
11.1.1 如何讀文本文件?
11.1.2 如何寫(xiě)文本文件?
11.1.3 如何讀寫(xiě)二進(jìn)制文件?
11.1.4 如何刪除文件?
11.2 文本處理
11.2.1 是否支持正規(guī)表達(dá)式?
11.3 Internet
11.3.1 如何下載網(wǎng)頁(yè)?
11.3.2 如何使用代理服務(wù)器 (PRoxy)?
11.4 xml
11.4.1 是否支持 DOM?
11.4.2 是否支持 SAX?
11.4.3 是否支持 XPath?
11.5 線程
11.5.1 是否支持多線程?
11.5.2 如何產(chǎn)生一個(gè)線程?
11.5.3 如何停止一個(gè)線程?
11.5.4 怎樣使用線程池?
11.5.5 怎樣知道我的線程池工作項(xiàng)目是在何時(shí)完成的?
11.5.6 怎樣防止對(duì)數(shù)據(jù)的并發(fā)訪問(wèn)?
11.6 跟蹤
11.6.1 有內(nèi)置的跟蹤/日志支持嗎?
11.6.2 能否將跟蹤輸出重定向到一個(gè)文件?
11.6.3 能否定制跟蹤的輸出?
 
12. 資源
12.1 從哪里可以獲得關(guān)于 .NET 的詳情?
12.2 示例代碼和實(shí)用程序 
 

1. 簡(jiǎn)介
1.1 什么是 .NET?
很難用一句話來(lái)講清楚。根據(jù) Microsoft 的說(shuō)法,.NET 是一個(gè)“革命性的新平臺(tái),建立在開(kāi)放的 Internet 協(xié)議和標(biāo)準(zhǔn)之上,通過(guò)工具和服務(wù)將計(jì)算和通訊以嶄新的方式融合到一起” 。

更為實(shí)際的定義是:.NET 是一個(gè)開(kāi)發(fā)和運(yùn)行軟件的新環(huán)境,便于開(kāi)發(fā)基于 Web 的服務(wù),擁有豐富的運(yùn)行庫(kù)服務(wù)以支持用多種編程語(yǔ)言編寫(xiě)的組件,具有跨語(yǔ)言和跨平臺(tái)的互操作能力。

注意,本文中使用術(shù)語(yǔ)“.NET”時(shí),它僅指新的 .NET 運(yùn)行庫(kù)及其相關(guān)技術(shù)。有時(shí)我們也稱其為“.NET 框架”。本文不包括其它 Microsoft 正在往上添加 .NET 名字的任何現(xiàn)有的產(chǎn)品和技術(shù) (例如 SQL Server.NET)。

 

1.2 .NET 只是 Windows DNA 的一個(gè)新名字嗎?
不。在很多地方,Windows DNA 僅僅是指使用現(xiàn)有技術(shù)的一種途徑(即所謂的三階式途徑)的市場(chǎng)術(shù)語(yǔ)。.NET 更為急進(jìn),并且包括一個(gè)完整的軟件開(kāi)發(fā)和運(yùn)行庫(kù)框架。

 

1.3 .NET 只適用于建立 Web 網(wǎng)站嗎?
不。如果你編寫(xiě)任何 Windows 軟件 (使用 ATL/COM、MFC、VB 甚至 Win32 裸接口),.NET 都可能為你正在做的事情提供可行的選擇 (或補(bǔ)充)。當(dāng)然,如果你就是在開(kāi)發(fā) Web 網(wǎng)站,.NET 有很多令你感興趣的東西—不僅僅是 asp+。

 

1.4 .NET 是在什么時(shí)候宣布的?
在 2000 年 6 月 22 日舉行的 Forum 2000 論壇上,Bill Gates 做了一次 演說(shuō),勾畫(huà)了 .NET 的“前景”。2000 年 7 月的 PDC 會(huì)議上針對(duì) .NET 技術(shù)做了很多會(huì)談,會(huì)談代表得到了包含 .NET Framework/SDK 和 Visual Studio 7 預(yù)覽版的光盤(pán)。

 

1.5 .NET 將在何時(shí)發(fā)布?
預(yù)計(jì)是在 2001 年的下半年。

 

1.6 如何開(kāi)發(fā) .NET 應(yīng)用程序?
.NET Framework SDK 包含可用于建立 .NET 應(yīng)用程序的命令行編譯器和實(shí)用程序。Visual Studio 的下一版本 (稱為 Visual Studio 7 或 Visual Studio.NET) 將完全集成對(duì) .NET 開(kāi)發(fā)的支持。

 

1.7 可以從哪里下載 .NET SDK 和 Visual Studio 7?
http://msdn.microsoft.com/net 可以下載 SDK 的 Beta 1 版。如果你是 MSDN Universal 訂戶,你還可以下載 Visual Studio 7 的 Beta 1 版。

 

1.8 .NET 中的關(guān)鍵技術(shù)是什么?
asp.net、CLR (Common Language Runtime—通用語(yǔ)言運(yùn)行庫(kù))、C# (新一代的類-java 語(yǔ)言)、SOAP、XML、ADO.NET、多語(yǔ)言支持 (Eiffel、COBOL 等等)

 

1.9 .NET 框架將運(yùn)行在什么平臺(tái)上?
Beta 1 支持在 Windows 2000、NT4 SP6a, Windows Me 和 Windows 98 上進(jìn)行開(kāi)發(fā)。Windows 95 支持運(yùn)行庫(kù)。

Microsoft 將按照和 .NET 運(yùn)行庫(kù)相似的時(shí)間表發(fā)布一個(gè)新版本 Windows。它的代號(hào)是“Whistler”,在很大程度上是對(duì) Windows 2000 的擴(kuò)充性更新,對(duì) GUI 有重要的改變。Microsoft 將以“.NET-enabled”作為新操作系統(tǒng)的賣點(diǎn),但看起來(lái)它沒(méi)有和 .NET 運(yùn)行庫(kù)綁在一起。如果 .NET 運(yùn)行庫(kù)能及時(shí)完成,它將包含在 Whistler 之內(nèi);否則,Whistler 將單獨(dú)發(fā)貨。

 

1.10 .NET 框架支持什么語(yǔ)言?
開(kāi)始 Microsoft 將提供 C#、C++、VB 和 JScript 編譯器。其它供應(yīng)商宣布他們有意開(kāi)發(fā)像 COBOL、Eiffel、Perl、Smalltalk 和 Python 等語(yǔ)言的 .NET 編譯器。

 

1.11 .NET 框架符合標(biāo)準(zhǔn)化趨勢(shì)嗎?
C# 以及稱為“通用語(yǔ)言基礎(chǔ)結(jié)構(gòu)”的一些東西的推薦標(biāo)準(zhǔn)草案已經(jīng)提交給了 ECMA。參見(jiàn) http://msdn.microsoft.com/net/ecma/

 

2. 基本術(shù)語(yǔ)
2.1 什么是 CLR?
CLR = Common Language Runtime—通用語(yǔ)言運(yùn)行庫(kù)。CLR 是一組標(biāo)準(zhǔn)資源集合,無(wú)論編程語(yǔ)言是什么,所有 (理論上) .NET 程序都能從中獲益。Robert Schmidt (Microsoft) 在他的 MSDN PDC# 文章 中列出了以下 CLR 資源:

面向?qū)ο蟮木幊棠P?(繼承、多態(tài)、異常處理、垃圾收集)
安全模型
類型系統(tǒng)
所有的 .NET 基礎(chǔ)類
許多 .NET 框架類
開(kāi)發(fā)、調(diào)試和測(cè)評(píng)工具
運(yùn)行和代碼管理
IL-機(jī)器語(yǔ)言 轉(zhuǎn)換器和優(yōu)化器

這些的含義是,在 .NET 世界里,不同的編程語(yǔ)言將在能力上比過(guò)去任何時(shí)候都更平等,雖然顯然不是所有語(yǔ)言都支持所有 CLR 服務(wù)。

 

2.2 什么是 CTS?
CTS = Common Type System—通用類型系統(tǒng)。它是指 .NET 運(yùn)行庫(kù)所理解、并且隨后 .NET 應(yīng)用程序可以使用的一系列類型。然而,注意不是所有的 .NET 語(yǔ)言都將支持 CTS 中的所有類型。CTS 是 CLS 的超集。

 

2.3 什么是 CLS?
CLS = Common Language Specification—通用語(yǔ)言規(guī)范。它是預(yù)計(jì)所有 .NET 語(yǔ)言都支持的一個(gè) CTS 的子集。這一思想是讓使用 CLS-相容類型的任何程序和以任何語(yǔ)言編寫(xiě)的 .NET 程序可以互相操作。

理論上它能允許在不同的 .NET 語(yǔ)言之間有緊密的互操作性—例如允許從一個(gè) VB 類里繼承一個(gè) C# 類。

 

2.4 什么是 IL?
IL = Intermediate Language—中間語(yǔ)言。又稱為 MSIL。所有 .NET 源代碼 (使用任何語(yǔ)言) 被編譯為 IL。然后在軟件的安裝點(diǎn)上或者運(yùn)行時(shí),IL 由即時(shí) (JIT) 編譯器轉(zhuǎn)換為機(jī)器碼。

 

2.5 什么是 C#?
C# 是在 .NET 框架中運(yùn)行的一種新語(yǔ)言。在他們的“C# 簡(jiǎn)介”白皮書(shū)中,Microsoft 這樣描述 C#:

“C# 是從 C 和 C++ 派生出來(lái)的一種簡(jiǎn)單的、面向?qū)ο蟮摹⒉⑶沂穷愋桶踩默F(xiàn)代編程語(yǔ)言。C# (發(fā)音為‘C sharp’) 牢固地根植于在 C 和 C++ 家族之樹(shù),將很快為 C 和 C++ 程序員所熟悉。C# 幫助開(kāi)發(fā)者將 Visual Basic 的高生產(chǎn)率和 C++ 的直接控制能力結(jié)合起來(lái)。”

將以上引言中的“C#”換成“Java”,你會(huì)發(fā)現(xiàn)這句陳述依然很正確 :)。

假如你是一位 C++ 程序員,你可能想看看我的 C# FAQ。

 

2.6 在 .NET 范疇里,“被管理”是什么含義?
術(shù)語(yǔ)“被管理”導(dǎo)致了很多誤解。在 .NET 里的不同地方都使用了它,分別指相互差別不大的不同東西。

被管理代碼:.NET 框架為運(yùn)行在其上的程序提供了幾個(gè)核心的運(yùn)行服務(wù)—例如異常處理和安全性。為使這些服務(wù)能工作,代碼必須提供運(yùn)行時(shí)的最低程度的一些信息。這樣的代碼被稱為被管理代碼。默認(rèn)情況下,所有 C#、Visual Basic.NET 和 JScript.NET 代碼都是被管理代碼。如不指明,VS7 C++ 代碼不是被管理代碼,但能通過(guò)一個(gè)命令行開(kāi)關(guān) (/com+) 使編譯器產(chǎn)生被管理代碼。

被管理數(shù)據(jù):是指由 .NET 運(yùn)行庫(kù)的垃圾收集器分配和回收的數(shù)據(jù)。C#、VB.NET 和 JScript.NET 數(shù)據(jù)總是被管理的。即使使用了 /com+ 開(kāi)關(guān),默認(rèn)情況下 VS7 C++ 數(shù)據(jù)也不是被管理的,但可以使用 __gc 關(guān)鍵字將其指定為被管理數(shù)據(jù)。

被管理類:通常在 C++ 的 Managed Extensions (ME) 范疇中涉及。使用 ME C++ 時(shí),可以用 __gc 關(guān)鍵字將其指定為被管理的。名副其實(shí),該類的實(shí)例所占用的內(nèi)存由垃圾收集器管理,但還不止如此。該類還成為了完全的 .NET 團(tuán)體的成員,同時(shí)帶來(lái)了好處和限制。好處之一是獲得了與其它語(yǔ)言編寫(xiě)的類之間的互操作性—例如,一個(gè)被管理 C++ 類可以繼承 VB 類。限制之一是被管理類只能繼承一個(gè)基類。

 

2.7 什么是映像?
所有的 .NET 編譯器都產(chǎn)生關(guān)于它們所產(chǎn)生的模塊中的類型定義的特殊數(shù)據(jù)。這些特殊數(shù)據(jù)同模塊封裝在一起 (隨后模塊被封裝到元件中),可以通過(guò)稱為映像 的機(jī)制來(lái)訪問(wèn)。System.Reflection 命名空間中包含向模塊或元件詢問(wèn)其類型的類。

使用映像來(lái)訪問(wèn) .NET 的特殊數(shù)據(jù)同使用 ITypeLib/ITypeInfo 來(lái)訪問(wèn) COM 中的類型庫(kù)數(shù)據(jù)非常相似,而且使用的目的也很相似—例如確定數(shù)據(jù)類型大小,以便在上下文、進(jìn)程、機(jī)器的邊界間調(diào)度它們。

映像還可以被用來(lái)動(dòng)態(tài)調(diào)用方法 (參見(jiàn) System.Type.InvokeMember),甚至在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建類型 (參見(jiàn) System.Reflection.Emit.TypeBuilder )。

 

3. 元件
3.1 什么是元件?
元件有時(shí)被描述為一個(gè)邏輯上的 .EXE 或 .DLL,它可以是任何一個(gè)應(yīng)用程序 (有一個(gè)主入口點(diǎn)) 或庫(kù)。一個(gè)元件由一個(gè)或多個(gè)文件組成 (dll、exe、html 文件等等),表示一組資源、類型定義以及這些類型的實(shí)現(xiàn)。一個(gè)元件也可以包含對(duì)其它元件的引用。這些資源、類型和引用在稱為清單的一個(gè)數(shù)據(jù)塊中描述。清單是元件的一部分,這樣一來(lái)元件就是自描述的。

元件的一個(gè)重要方面使他們是一個(gè)類型的唯一標(biāo)志的一部分。類型的唯一標(biāo)志是將它所在的元件和類型名組合在一起得到的。這就是說(shuō),例如,如果元件 A 輸出了一個(gè)稱為 T 的類型,同時(shí)元件 B 輸出了一個(gè)也稱為 T 的類型,.NET 運(yùn)行庫(kù)將它們視為完全不同的兩個(gè)類型。此外,不要混淆元件和命名空間—命名空間僅僅是組織類型名字的一種層次化方法。對(duì)于運(yùn)行庫(kù),不論使用哪一個(gè)命名空間來(lái)組織名字,類型名就是類型名。從運(yùn)行庫(kù)來(lái)看,是元件加上類型名 (無(wú)論類型名屬于哪個(gè)命名空間) 唯一地標(biāo)識(shí)出一個(gè)類型。

元件在 .NET 的安全方面也很重要—許多安全限制是在元件的邊界上實(shí)施的。

最后,元件是 .NET 中版本控制的單元—詳情見(jiàn)下文。

 

3.2 怎樣創(chuàng)建元件?
創(chuàng)建元件最簡(jiǎn)單的方法是直接使用 .NET 編譯器。例如,以下 C# 程序:

public class CTest
{
    public CTest()
    {
        System.Console.WriteLine( "Hello from CTest" );
    }
}
能用以下方法編譯為一個(gè)庫(kù)元件 (dll):

csc /t:library ctest.cs
通過(guò)運(yùn)行 .NET SDK 所帶的“IL 反匯編”工具,你能看到元件的內(nèi)容。

另外你也能把你的源代碼編譯成模塊,然后使用元件連接器 (al.exe) 將模塊組合成一個(gè)元件。對(duì) C# 編譯器,/target:module 開(kāi)關(guān)可以指定產(chǎn)生模塊而不是元件。

 

3.3 私有元件和共享元件有什么不同?
空間分配和可見(jiàn)性:私有元件通常由一個(gè)應(yīng)用程序使用,被存儲(chǔ)到這個(gè)應(yīng)用程序的目錄或其下的子目錄之下。共享元件通常存儲(chǔ)到全局的元件緩沖區(qū)中,這里是 .NET 運(yùn)行庫(kù)維護(hù)的元件的儲(chǔ)藏所。共享元件通常是許多應(yīng)用程序都要用到的代碼庫(kù),例如 .NET 框架類。
 
版本控制:運(yùn)行庫(kù)只對(duì)共享元件實(shí)施版本約束,而不對(duì)私有元件實(shí)施。
 

3.4 元件如何相互找到?
通過(guò)尋找目錄路徑。有幾個(gè)因素會(huì)影響路徑 (比如 AppDomain 宿主、應(yīng)用程序配置文件等),但對(duì)于私有元件,搜索路徑通常是應(yīng)用程序的目錄及其子目錄。對(duì)于共享元件,搜索路徑通常和私有元件的一樣,再加上共享元件緩沖區(qū)。

 

3.5 元件版本如何起作用?
每個(gè)元件由一個(gè)稱為兼容性版本的版本號(hào)。同樣,對(duì)元件的引用 (從另一個(gè)元件) 包括被引用元件的名稱和版本。

版本號(hào)有四個(gè)數(shù)字部分 (例如 5.5.2.33)。前兩部分不相同的元件被視為不兼容的。如果前兩部分相同,但第三部分不同,元件被認(rèn)為“可能兼容”。如果僅僅第四部分不同,則元件被視為是兼容的。然而,這只是默認(rèn)的指導(dǎo)方針—是 版本策略決定施用這些規(guī)則的范圍。版本策略可以在應(yīng)用程序配置文件中指定。

記住:版本控制僅僅針對(duì)于共享元件,而不對(duì)私有元件。

 

4. 應(yīng)用程序域
4.1 什么是應(yīng)用程序域?
應(yīng)用程序域 (AppDomain) 可以被看作一個(gè)輕型的進(jìn)程。在一個(gè) Win32 進(jìn)程中可以存在多個(gè) AppDomain。AppDomain 的主要目的是將應(yīng)用程序和其它應(yīng)用程序隔離開(kāi)來(lái)。

通過(guò)使用獨(dú)立的地址空間,Win32 進(jìn)程提供隔離性。這種方法很有效,但開(kāi)銷很大并且伸縮性不好。.NET 運(yùn)行庫(kù)通過(guò)控制對(duì)內(nèi)存的是用來(lái)施加 AppDomain 隔離—AppDomain 中的所有內(nèi)存是由 .NET 運(yùn)行庫(kù)來(lái)管理的,所以運(yùn)行庫(kù)可以確保 AppDomain 之間不能訪問(wèn)彼此的內(nèi)存。

 

4.2 如何創(chuàng)建 AppDomain?
AppDomains 通常有宿主創(chuàng)建。宿主包括 Windows Shell、ASP+ 和 IE。當(dāng)你從命令行運(yùn)行一個(gè) .NET 應(yīng)用程序時(shí),宿主是 Shell。Shell 為每個(gè)應(yīng)用程序創(chuàng)建一個(gè)新的 AppDomain。

AppDomains 也可以由 .NET 應(yīng)用程序來(lái)顯式創(chuàng)建。這里是一個(gè)創(chuàng)建 AppDomain 的一個(gè) C# 例子,它創(chuàng)建對(duì)象的一個(gè)實(shí)例,并隨后執(zhí)行對(duì)象的一個(gè)方法:

using System;
using System.Runtime.Remoting;

public class CAppDomainInfo : MarshalByRefObject
{
    public string GetAppDomainInfo()
    {
        return "AppDomain = " + AppDomain.CurrentDomain.FriendlyName;
    }

}

public class App
{
    public static int Main()
    {
        AppDomain ad = AppDomain.CreateDomain( "Andy's new domain", null, null );
        ObjectHandle oh = ad.CreateInstance( "appdomaintest.exe", "CAppDomainInfo" );
        CAppDomainInfo adInfo = (CAppDomainInfo)(oh.Unwrap());
        string info = adInfo.GetAppDomainInfo();
       
        Console.WriteLine( "AppDomain info: " + info );
        return 0;
    }
}
 

4.3 我能編寫(xiě)自己的 .NET 宿主嗎?
能。關(guān)于怎樣來(lái)做的例子,看看 Jason Whittington 和 Don Box 開(kāi)發(fā)的 dm.net moniker 的源代碼 (http://staff.develop.com/jasonw/clr/readme.htm)。在 .NET SDK 中也有一個(gè)叫作 CorHost 的代碼示例。

 

5. 垃圾收集
5.1 什么是垃圾收集?
垃圾收集是一個(gè)系統(tǒng),運(yùn)行庫(kù)組件通過(guò)它來(lái)管理對(duì)象的生存周期和它們占用的堆內(nèi)存。對(duì) .NET 而言它并不是一個(gè)新概念—Java 和許多其它語(yǔ)言/運(yùn)行庫(kù)使用垃圾收集已經(jīng)有一段時(shí)間了。

 

5.2 對(duì)對(duì)象的最后一個(gè)引用撤銷后,它并不一定立即被破壞,對(duì)嗎?
是的。垃圾收集器并不提供銷毀對(duì)象并是放其內(nèi)存的時(shí)間保證。

關(guān)于 C# 中隱含的非確定化對(duì)象析構(gòu),Chris Sells 有一個(gè)令人感興趣的線索:http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&P=R24819

2000 年 10 月,Microsoft 的 Brian Harry 貼出了一個(gè)針對(duì)這個(gè)問(wèn)題的很長(zhǎng)的分析:http://discuss.develop.com/archives/wa.exe?A2=ind0010A&L=DOTNET&P=R28572

Chris Sells 對(duì) Brian 貼子的答復(fù)在這里:http://discuss.develop.com/archives/wa.exe?A2=ind0010C&L=DOTNET&P=R983

 

5.3 .NET 為什么不提供確定化的析構(gòu)?
因?yàn)槔占惴ā?NET 的垃圾收集器通過(guò)周期地掃描應(yīng)用程序正在使用的所有對(duì)象的列表來(lái)工作。掃描過(guò)程中所有未被發(fā)現(xiàn)的對(duì)象就可以被銷毀并釋放內(nèi)存。當(dāng)對(duì)對(duì)象的最后一個(gè)引用撤銷后,算法的這種實(shí)現(xiàn)使運(yùn)行庫(kù)不能立即得到通知—它只能在下一次清理堆時(shí)發(fā)現(xiàn)。

而且,這種算法盡可能少地進(jìn)行垃圾收集,以便工作得最有效率。通常,堆容量的消耗會(huì)觸發(fā)收集過(guò)程。

 

5.4 在 .NET 中缺少確定化的析構(gòu)有問(wèn)題嗎?
這確實(shí)會(huì)影響組件的設(shè)計(jì)。如果你的對(duì)象需要昂貴或緊缺的資源 (例如對(duì)數(shù)據(jù)庫(kù)的鎖定),你需要提供某種方法讓客戶端在工作完成后能告訴對(duì)象以釋放資源。Microsoft 建議,為此目的你應(yīng)提供一個(gè)稱為 Dispose () 的方法。然而,這樣會(huì)在分布式對(duì)象中引起問(wèn)題—在一個(gè)分布式系統(tǒng)中由誰(shuí)來(lái)調(diào)用 Dispose () 方法?需要有某種形式的引用-計(jì)數(shù)機(jī)制或所有者管理機(jī)制來(lái)處理分布式對(duì)象—不幸的是運(yùn)行庫(kù)對(duì)此愛(ài)莫能助。

 

5.5 確定化的析構(gòu)是否影響在被管理代碼中使用 COM 對(duì)象?
是的。從被管理代碼中使用 COM 對(duì)象時(shí),你實(shí)際上是依賴?yán)占鱽?lái)最終釋放你的對(duì)象。如果你的 COM 對(duì)象占有昂貴的資源且只能在最終釋放對(duì)象后才能釋放,你可能需要在你的對(duì)象上提供一個(gè)新接口以支持顯式的 Dispose () 方法。

 

5.6 我聽(tīng)說(shuō)應(yīng)該避免使用 Finalize 方法,那么是否應(yīng)該在我的類理實(shí)現(xiàn) Finalize?
對(duì)垃圾收集器而言,擁有 Finalize 方法的對(duì)象比沒(méi)有此方法的對(duì)象需要做更多的工作。同時(shí)也不保證對(duì)象 Finalized 的次序,所以對(duì)于從 Finalized 方法訪問(wèn)其它對(duì)象有不同的看法。最后,不能保證 Finalized 方法一定能被調(diào)用。所以,永遠(yuǎn)不應(yīng)該依賴它來(lái)清理對(duì)象的資源。

Microsoft 建議使用以下方式:

public class CTest
{
    public override void Dispose()
    {
        ... // Cleanup activities
        GC.SuppressFinalize(this);
    }
   
    protected override void Finalize()
    {
        Dispose();
    }
}
一般情況下客戶端調(diào)用 Dispose (),對(duì)象的資源被釋放,并且通過(guò)調(diào)用 SuppressFinalize (),垃圾收集器被免除了對(duì)它進(jìn)行 Finalize 的義務(wù)。在最不利的情況下,即客戶端忘記了調(diào)用 Dispose (),有很大的機(jī)會(huì)通過(guò)垃圾收集器調(diào)用 Finalize () 來(lái)最終釋放對(duì)象的資源。由于垃圾收集算法的缺陷,這看起來(lái)像是相當(dāng)合理的處理辦法了。

 

5.7 我有控制垃圾收集算法的手段嗎?
有一點(diǎn)。System.GC 類提供了一對(duì)有趣的方法。第一個(gè)是 Collect 方法—它強(qiáng)制垃圾收集器立即收集所有未被引用的對(duì)象。另一個(gè)是 RequestFinalizeOnShutdown (),它告訴垃圾收集器在應(yīng)用程序關(guān)閉時(shí)一定要對(duì)每個(gè)對(duì)象運(yùn)行 Finalize () 方法。在應(yīng)用程序關(guān)閉時(shí),垃圾收集器一般優(yōu)先選擇快速的推出方式而不是調(diào)用 Finzlize (),所以這個(gè)方法能手工強(qiáng)制運(yùn)行庫(kù)多負(fù)一點(diǎn)責(zé)任。

如果你想驗(yàn)證這不僅僅是理論上的說(shuō)法,是一十下面的測(cè)試程序:

using System;

class CTest
{
    protected override void Finalize()
    {
        Console.WriteLine( "This is the Finalizer." );
    }
}

class Capplication
{
    public static void Main()
    {
        Console.WriteLine( "This is Main." );
        CTest test = new CTest();
       
        // GC.RequestFinalizeOnShutdown();
    }
}
運(yùn)行此程序,然后再去掉 GC.RequestFinalizeOnShutdown() 這一行前面的注釋標(biāo)記并重新運(yùn)行,注意有什么不同……

 

5.8 我怎么知道垃圾收集器在做什么?
.NET 運(yùn)行庫(kù)中很多令人感興趣的統(tǒng)計(jì)通過(guò) 'COM+ Memory' 性能對(duì)象輸出。使用 Performance Monitor 查看它們。

 

6. 屬性
6.1 什么是屬性?
最少有兩種類型的 .NET 屬性。第一類我稱其為 metadata 屬性—它允許將某些數(shù)據(jù)附加到類或方法上。這些數(shù)據(jù)稱為類的 metadata 的一部分,并且可以像類的其它 metadata 一樣通過(guò)映射來(lái)訪問(wèn)。metadata 的另一種屬性是 [serializable],將它附加到類上表示類的實(shí)例可以被串行化。

[serializable] public class CTest {}
另一種類型的屬性是上下文屬性。上下文類型的屬性使用和 metadata 相似的語(yǔ)法,但實(shí)際上它們是不同的。上下文類型屬性提供一種解釋機(jī)制,通過(guò)這種機(jī)制,實(shí)例的活動(dòng)和方法調(diào)用可以是預(yù)先處理和/或隨后處理的。如果你了解 Keith Brown 的通用委托器你可能熟悉這種思想。

 

6.2 我能創(chuàng)建自己的 metadata 屬性嗎?
是的。簡(jiǎn)單地從 System.Attribute 導(dǎo)出一個(gè)類并將其標(biāo)記為 AttributeUsage 屬性。例如:

[AttributeUsage(AttributeTargets.Class)]
public class InspiredByAttribute : System.Attribute
{
    public string InspiredBy;

    public InspiredByAttribute( string inspiredBy )
    {
        InspiredBy = inspiredBy;
    }
}


[InspiredBy("Andy Mc's brilliant .NET FAQ")]
class CTest
{
}
class CApp
{
    public static void Main()
    {
      object[] atts = typeof(CTest).GetCustomAttributes();
            foreach( object att in atts )
         if( att is InspiredByAttribute )
        Console.WriteLine( "Class CTest was inspired by {0}", _
           ((InspiredByAttribute)att).InspiredBy  );
    }
}
 

6.3 我能創(chuàng)建自己的 context 屬性嗎?
是的。看看 http://www.develop.com/dbox/dotnet/threshold/ 處的 Don Box 的例子 (叫作 CallThreshold) 和 http://www.razorsoft.net/ 處的 Perter Drayton 的 Tracehook.NET

 

7. 代碼訪問(wèn)安全性
7.1 什么是代碼訪問(wèn)安全性 (CAS)?
CAS 是 .NET 安全性模型的一部分,它確定一段代碼是否允許被運(yùn)行,以及當(dāng)它運(yùn)行是可以使用什么資源。例如,CAS 可以防止一個(gè) .NET 的 Web applet 將你的硬盤(pán)格式化。

 

7.2 CAS 如何起作用?
CAS 安全策略設(shè)計(jì)兩個(gè)關(guān)鍵概念—代碼組和權(quán)限。每個(gè) .NET 元件是特定 代碼組的成員,并且每個(gè)代碼組被授予由有名權(quán)限集所指定的權(quán)限。

例如,使用默認(rèn)的安全策略時(shí),一個(gè)從 Web 站點(diǎn)下載的控件屬于“Zone - Internet”代碼組,它保持由有名權(quán)限集“Internet”所定義的權(quán)限。(自然,有名權(quán)限集“Internet”表示一組受到嚴(yán)格限制的權(quán)限。)

 

7.3 誰(shuí)定義 CAS 代碼組?
Microsoft 定義了一些默認(rèn)代碼組,但你可以改變這些甚至創(chuàng)建你自己的代碼組。要想看到你的系統(tǒng)中定義的代碼組,可以從命令橫行運(yùn)行“caspol -lg”命令。再我的系統(tǒng)里它看起來(lái)像這些:

Level = Machine

Code Groups:

1.  All code: Nothing
   1.1.  Zone - MyComputer: FullTrust
      1.1.1.  Honor SkipVerification requests: SkipVerification
   1.2.  Zone - Intranet: LocalIntranet
   1.3.  Zone - Internet: Internet
   1.4.  Zone - Untrusted: Nothing
   1.5.  Zone - Trusted: Internet
   1.6.  StrongName - 0024000004800000940000000602000000240000525341310004000003
000000CFCB3291AA715FE99D40D49040336F9056D7886FED46775BC7BB5430BA4444FEF8348EBD06
F962F39776AE4DC3B7B04A7FE6F49F25F740423EBF2C0B89698D8D08AC48D69CED0FC8F83B465E08
07AC11EC1DCC7D054E807A43336DDE408A5393A48556123272CEEEE72F1660B71927D38561AABF5C
AC1DF1734633C602F8F2D5: Everything
注意代碼組的層次—頂層 ('All code') 是最通用的,它隨后分為幾個(gè)組,每個(gè)還可以再分。同時(shí)注意,和一般的想象不同,子組可以被賦予比它的上級(jí)更寬的權(quán)限集。

 

7.4 如何定義自己的代碼組?
使用 caspol。例如,假定你信任來(lái)自 www.mydomain.com 的代碼,并且希望它對(duì)你的系統(tǒng)擁有完全的訪問(wèn)權(quán),但是希望對(duì)其它 Internet 站點(diǎn)保持默認(rèn)的限制。要實(shí)現(xiàn)這些,你可以在“Zone - Internet”組中增加一個(gè)子組,就像下面那樣:

caspol -ag 1.3 -site www.mydomain.com FullTrust
現(xiàn)在如果你運(yùn)行 caspol -lg 就可以看到新的代碼組被增加為 1.3.1 組:

...
   1.3.  Zone - Internet: Internet
      1.3.1.  Site - www.mydomain.com: FullTrust
...
注意數(shù)字標(biāo)號(hào) (1.3.1) 只是 caspol 編出來(lái)以便能從命令行方便地操縱代碼組的。底層的運(yùn)行庫(kù)永遠(yuǎn)看不到它。

 

7.5 如何改變代碼組的權(quán)限集?
使用 caspol。如果你是機(jī)器的管理員,你能在 'machine' 層次上操作—這不僅意味著你所做的改變將成為機(jī)器的默認(rèn)設(shè)置,而且用戶不能把權(quán)限改得更寬。如果你是一個(gè)普通用戶 (不是管理員) 你仍然可以修改權(quán)限,但只能使它們變得更嚴(yán)格。例如,為使 intranet 代碼能做它們想做的事,你可能需要這樣:

caspol -cg 1.2 FullTrust
注意,因?yàn)?(在標(biāo)準(zhǔn)的系統(tǒng)里) 這比默認(rèn)的安全策略權(quán)限更大,你應(yīng)該在 machine 層次上做這些—在 user 層次上這樣做不起作用。

 

7.6 能否創(chuàng)建自己的權(quán)限集?
是的。使用 caspol -ap,指定一個(gè)包含權(quán)限集中所有的權(quán)限的 XML 文件。這里 是一個(gè)指定 'Everything' 權(quán)限集的示例文件—修改它以適應(yīng)你的需要,這樣可以節(jié)省一些時(shí)間。修改完成后,用以下方法將它添加到可用的權(quán)限集中:

caspol -ap samplepermset.xml
然后,用以下方法將此權(quán)限集施加到一個(gè)代碼組上:

caspol -cg 1.3 SamplePermSet
(默認(rèn)情況下,1.3 是 'Internet' 代碼組)

 

7.7 CAS 有問(wèn)題時(shí),如何診斷自己的程序?
caspol 有一組可能有用的選項(xiàng)。首先,使用 caspol -rsg,你能讓 caspol 告訴你一個(gè)元件屬于哪一個(gè)代碼組。類似地,使用 caspol -rsp,你能詢問(wèn)在特定元件上施加了什么權(quán)限。

 

7.8 我受不了 CAS 帶來(lái)的麻煩,能否關(guān)掉它?
是的,只要你是系統(tǒng)管理員。只要運(yùn)行:

caspol -s off
 

8. 中間語(yǔ)言 (IL)
8.1 我能看到元件的中間語(yǔ)言嗎?
是的。Microsoft 提供了一個(gè)稱為 Ildasm 的工具,它可以用來(lái)查看元件的 metadata 和 IL。

 

8.2 能否通過(guò)反向工程從 IL 中獲得源代碼?
是的。相對(duì)而言,從 IL 來(lái)重新生成高級(jí)語(yǔ)言源代碼 (例如 C#) 通常是很簡(jiǎn)單的。

 

8.3 如何防止別人通過(guò)反向工程獲得我的代碼?
目前唯一的辦法是運(yùn)行帶有 /owner 選項(xiàng)的 ilasm。這樣生成的元件的 IL 不能通過(guò) ildasm 來(lái)查看。然而,意志堅(jiān)定的代碼破譯者能夠破解 ildasm 或者編寫(xiě)自己的 ildasm 版本,所以這種方法只能嚇唬那些業(yè)余的破譯者。

不幸的事,目前的 .NET 編譯器沒(méi)有 /owner 選項(xiàng),所以要想保護(hù)你的 C# 或 VB.NET 元件,你需要像下面那樣做:

csc helloworld.cs
ildasm /out=temp.il helloworld.exe
ilasm /owner temp.il
(這個(gè)建議是 Hany Ramadan 貼到 DOTNET 上的。)

看起來(lái)過(guò)一段時(shí)間能有 IL 加密工具 (無(wú)論來(lái)自 Microsoft 或第三方)。這些工具會(huì)以這樣的方式來(lái)“優(yōu)化” IL:使反向工程變得更困難。

當(dāng)然,如果你是在編寫(xiě) Web 服務(wù),反向工程看起來(lái)就不再是一個(gè)問(wèn)題,因?yàn)榭蛻舨荒茉L問(wèn)你的 IL。

 

8.4 我能直接用 IL 編程嗎?
是的。Peter Drayton 在 DOTNET 郵件列表里貼出了這個(gè)簡(jiǎn)單的例子:

.assembly MyAssembly {}
.class MyApp {
  .method static void Main() {
    .entrypoint
    ldstr      "Hello, IL!"
    call       void System.Console::WriteLine(class System.Object)
    ret
  }
}
將其放入名為 hello.il 的文件中,然后運(yùn)行 ilasm hello.il,將產(chǎn)生一個(gè) exe 元件。

 

8.5 IL 能做到 C# 中做不到的事嗎?
是的。一些簡(jiǎn)單的例子是:你能拋出不是從 SystemException 導(dǎo)出的異常,另外你能使用非以零起始的數(shù)組。

 

9. 關(guān)于 COM
9.1 COM 消亡了嗎?
就像你在郵件列表中看到的那樣,這個(gè)主題導(dǎo)致了激烈的爭(zhēng)論。看看以下兩個(gè)地方:

http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&D=0&P=68241
http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&P=R60761

我的理解是:COM 包含很多內(nèi)容,并且對(duì)于不同的人而言它是不同的東西。但是對(duì)我來(lái)說(shuō),COM 基本上是關(guān)于一小段代碼如何找到另一小段代碼,以及當(dāng)它們相互找到后該如何相互通訊。COM 準(zhǔn)確地指明了這種定位和通訊該如何進(jìn)行。在完全由 .NET 對(duì)象構(gòu)成的“純” .NET 世界里,小段代碼依然相互尋找并相互交談,但它們不使用 COM 來(lái)做這些。它們使用在某些地方和 COM 很相像的一種模型—例如,類型信息保存在和組件封裝在一起的表單中,這和在 COM 組件中封裝一個(gè)類型庫(kù)十分相似。但它不是 COM。

所以,這里有什么問(wèn)題嗎?好吧,我確實(shí)不關(guān)心大多數(shù) COM 消失了—我不關(guān)心尋找組件不再和注冊(cè)表有關(guān),我也不使用 IDL 來(lái)定義我的借口。但有一件東西我不希望它消失—我不希望失去基于接口的開(kāi)發(fā)這種思想。照我看來(lái),COM 最強(qiáng)大的力量是它堅(jiān)持在接口和實(shí)現(xiàn)之間豎起鑄鐵般的隔墻。不幸的是,看來(lái) .NET 不再那樣堅(jiān)持—它允許你做基于接口的開(kāi)發(fā),但它并不堅(jiān)持。一些人可能會(huì)辯解說(shuō)有一個(gè)選擇總不會(huì)是壞事,可能他們是對(duì)的,但我不能不覺(jué)得這可能是一個(gè)退步。

 

9.2 DCOM 消亡了嗎?
差不多是,尤其是對(duì)于 .NET 開(kāi)發(fā)者。.NET 框架有一個(gè)不基于 DCOM 的新的遠(yuǎn)程模型。當(dāng)然 DCOM 還會(huì)在互操作場(chǎng)合下使用。

 

9.3 MTS/COM+ 消亡了嗎?
不。第一個(gè) .NET 版本考慮的是提供對(duì)現(xiàn)有 COM+ 服務(wù) (通過(guò)一個(gè)互操作層) 而不是使用 .NET 自己的服務(wù)來(lái)取代它們。很多工具和屬性被用以實(shí)現(xiàn)盡可能平滑的過(guò)渡。.NET SDK 的 PDC 版本包括對(duì)核心服務(wù) (JIT 活動(dòng)、事務(wù)) 的支持,但不包括一些高層服務(wù) (例如 COM+ 事件、隊(duì)列化組件)。

在一段時(shí)間內(nèi)看來(lái),互操作性可以預(yù)期是無(wú)縫集成的—這意味著一些服務(wù)將成為 CLR 的一部分,并且/或者意味著一些服務(wù)將以可管理代碼的形式重寫(xiě)并運(yùn)行在 CLR 的頂層。

關(guān)于這個(gè)主題,參見(jiàn) Joe Long 的貼子—Joe 是 Microsoft 的 COM+ 組的經(jīng)理。從這里開(kāi)始:

http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&P=R68370

 

9.4 能在 .NET 中使用 COM 組件嗎?
可以。可以通過(guò) Runtime Callable Wrapper (RCW) 從 .NET 中訪問(wèn) COM 組件。它通過(guò)將 COM 組件映射為與 .NET 兼容的接口來(lái)使 COM 接口可以被訪問(wèn)。對(duì)于 oldautomation 接口,可以自動(dòng)地從一個(gè)類型庫(kù)中產(chǎn)生。對(duì)于非 oleautomation 接口,可以開(kāi)發(fā)一個(gè)定制的 RCW,以便手工地將 COM 接口的類型映射為與 .NET 兼容的類型。

對(duì)于熟悉 ATL 的讀者,這里有一個(gè)簡(jiǎn)單的示例。首先,創(chuàng)建一個(gè) ATL 組件以實(shí)現(xiàn)以下 IDL:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(EA013F93-487A-4403-86EC-FD9FEE5E6206),
    helpstring("ICppName Interface"),
    pointer_default(unique),
    oleautomation
]

interface ICppName : IUnknown
{
    [helpstring("method SetName")] HRESULT SetName([in] BSTR name);
    [helpstring("method GetName")] HRESULT GetName([out,retval] BSTR *pName );
};

[
    uuid(F5E4C61D-D93A-4295-A4B4-2453D4A4484D),
    version(1.0),
    helpstring("cppcomserver 1.0 Type Library")
]
library CPPCOMSERVERLib
{
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    [
        uuid(600CE6D9-5ED7-4B4D-BB49-E8D5D5096F70), 
        helpstring("CppName Class")
    ]
    coclass CppName
    {
        [default] interface ICppName;
    };
};
建立了組件以后,你會(huì)得到一個(gè) typelibrary。在 typelibrary 上運(yùn)行 TLBIMP 實(shí)用程序,就像這樣:

tlbimp cppcomserver.tlb
如果成功,你會(huì)得到像這樣的信息:

Typelib imported successfully to CPPCOMSERVERLib.dll
現(xiàn)在你需要一個(gè) .NET 客戶端—我們用 C# 創(chuàng)建一個(gè)包含以下代碼的 .cs 文件:

using System;
using CPPCOMSERVERLib;

public class MainApp
{
    static public void Main()
    {
        CppName cppname = new CppName();
        cppname.SetName( "bob" );
        Console.WriteLine( "Name is " + cppname.GetName() );
    }
}
注意我們使用 typelibrary 的名字作為命名空間,COM 類的名字作為類名。我們也可以選擇使用 CPPCOMSERVERLib.CppName 作為類名而且不需要語(yǔ)句 using CPPCOMSERVERLib。

像這樣編譯以上 C# 代碼:

csc /r:cppcomserverlib.dll csharpcomclient.cs
注意,編譯被告知,引用我們剛才用 TLBIMP 從 typelibrary 產(chǎn)生的 DLL。

現(xiàn)在你應(yīng)該可以運(yùn)行 csharpcomclient.exe,并從控制臺(tái)得到如下輸出:

Name is bob
 

9.5 能在 COM 中使用 .NET 組件嗎?
可以。可以通過(guò)一個(gè) COM Callable Wraper (CCW) 從 COM 中訪問(wèn) .NET 組件。這和 RCW 很相似 (參見(jiàn)上一個(gè)問(wèn)題),但以相反的方向工作。同樣,如果它不能由 .NET 開(kāi)發(fā)工具自動(dòng)產(chǎn)生,或不想要自動(dòng)產(chǎn)生的行為邏輯,可以開(kāi)發(fā)一個(gè)定制的 CCW。為使 COM 可以“看見(jiàn)” .NET 組件,.NET 組件必須在注冊(cè)表里注冊(cè)。

這里是一個(gè)簡(jiǎn)單的例子。創(chuàng)建一個(gè)名為 testcomserver.cs 的 C# 文件并輸入下面的代碼:

using System;

namespace AndyMc
{
    public class CSharpCOMServer
    {
        public CSharpCOMServer() {}
        public void SetName( string name ) { m_name = name; }
        public string GetName() { return m_name; } 
        private string m_name;
    }         
}
然后編譯 .cs 文件:

csc /target:library testcomserver.cs
你會(huì)得到一個(gè) dll,這樣將它注冊(cè):

regasm testcomserver.dll /tlb:testcomserver.tlb
現(xiàn)在你需要?jiǎng)?chuàng)建一個(gè)客戶端程序來(lái)測(cè)試你的 .NET COM 組件。VBScript 可以—將以下內(nèi)容放到一個(gè)名為 comclient.vbs 的文件中:

Dim dotNetObj
Set dotNetObj = CreateObject("AndyMc.CSharpCOMServer")
dotNetObj.SetName ("bob")
MsgBox "Name is " & dotNetObj.GetName()
運(yùn)行此腳本:

wscript comclient.vbs
嘿!你得到一個(gè)顯示文本“Name is bob”的消息框。

(注意,編寫(xiě)此程序時(shí),看起來(lái)可以通過(guò)幾種路徑將 .NET 類作為 COM 組件訪問(wèn)—為了避免問(wèn)題,在 testcomserver.dll 相同的目錄下運(yùn)行 comclient.vbs。

一種替代的方法是使用 Jason Whittington 和 Don Box 開(kāi)發(fā)的 dm.net moniker。到這里 http://staff.develop.com/jasonw/clr/readme.htm 查看。

 

9.6 在 .NET 的世界中 ATL 是多余的嗎?
是的。如果你在編寫(xiě) .NET 框架內(nèi)的應(yīng)用程序。當(dāng)然許多開(kāi)發(fā)者希望繼續(xù)使用 ATL 來(lái)編寫(xiě) .NET 框架以外的 C++ COM 組件,但當(dāng)你在 .NET 框架內(nèi)時(shí)你差不多總是希望使用 C#。在 .NET 世界里,原始的 C++ (以及基于它的 ATL) 并沒(méi)有太多的地位—它太直接了,并且提供了太多的適應(yīng)性,以至于運(yùn)行庫(kù)不能管理它。

 

10. 雜項(xiàng)
10.1 .NET 的遠(yuǎn)程計(jì)算如何工作?
.NET 的遠(yuǎn)程計(jì)算涉及通過(guò)通道發(fā)送消息。兩種標(biāo)準(zhǔn)的通道是 HTTP 和 TCP。僅僅在局域網(wǎng)上才傾向于使用 TCP—HTTP 能在局域網(wǎng)和廣域網(wǎng) (internet) 上使用。

現(xiàn)在提供了對(duì)多種消息串行化格式的支持,例如 SOAP (基于 XML) 和二進(jìn)制格式。默認(rèn)情況下,HTTP 通道使用 SOAP (通過(guò) .NET 運(yùn)行庫(kù)的 Serialization SOAP Formatter),而 TCP 通道使用二進(jìn)制格式 (通過(guò) .NET 運(yùn)行庫(kù)的 Serialization Binary Formatter)。但每個(gè)通道可以使用任一串行化格式。

這里是遠(yuǎn)程訪問(wèn)的一些方式:

SingleCall。每個(gè)來(lái)自客戶端的請(qǐng)求由一個(gè)新對(duì)象服務(wù)。當(dāng)請(qǐng)求完成后對(duì)象被丟棄。可以在 ASP+ 環(huán)境中使用 ASP+ 國(guó)家服務(wù)來(lái)保存應(yīng)用程序或會(huì)話的國(guó)家,從而使這種模型 (無(wú)國(guó)家之分的) 變成有國(guó)家支持的。
 
Singleton。所有來(lái)在客戶端的請(qǐng)求由單一的服務(wù)器對(duì)象處理。
 
Client-activated object。這是老的有國(guó)家支持的 (D)COM 模型,這里客戶端受到一個(gè)遠(yuǎn)端對(duì)象的引用并保留此引用 (以保持遠(yuǎn)端對(duì)象的生存),直到對(duì)它的訪問(wèn)完成。
對(duì)象的分布式垃圾收集由稱為“基于租用的生命周期”管理。每個(gè)對(duì)象擁有一個(gè)租用時(shí)間,這個(gè)時(shí)間到達(dá)時(shí),從 .NET 運(yùn)行庫(kù)的遠(yuǎn)程子結(jié)構(gòu)斷開(kāi)對(duì)象。對(duì)象有默認(rèn)的更新時(shí)間—從客戶端發(fā)起的成功調(diào)用會(huì)更新租用時(shí)間。客戶端也可以顯示地更新租用時(shí)間。

如果你對(duì)使用 XML-RPC 來(lái)代替 SOAP,可以看看 Charles Cook 在 http://www.cookcomputing.com/xmlrpc/xmlrpc.shtml 的 XML-RPC.Net 站點(diǎn)。

 

10.2 如何在 .NET 程序中獲得 Win32 API?
使用 P/Invoke。它使用了和 COM 互操作性相似的技術(shù),但被用來(lái)訪問(wèn)靜態(tài) DLL 入口點(diǎn)而不是 COM 對(duì)象。以下是一個(gè)調(diào)用 Win32 MessageBox 函數(shù)的 C# 程序示例:

using System;
using System.Runtime.InteropServices;

class MainApp
{
    [dllimport("user32.dll", EntryPoint="MessageBox", SetLastError=true, CharSet=CharSet.Auto)]
    public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);

    public static void Main()
    {
        MessageBox( 0, "Hello, this is PInvoke in Operation!", ".NET", 0 );
    }
}
 

11. 類庫(kù)
11.1 文件 I/O
11.1.1 如何讀文本文件?
首先,使用 System.IO.FileStream 對(duì)象打開(kāi)文件:

FileStream fs = new FileStream( @"c:/test.txt", FileMode.Open, Fileaccess.Read );
FileStream 繼承于 Stream,所以你可以用一個(gè) StreamReader 對(duì)象把 FileStream 對(duì)象包裝起來(lái)。這樣為一行一行地進(jìn)行流處理提供了一個(gè)良好的界面:

StreamReader sr = new StreamReader( fs );
string curLine;
while( (curLine = sr.ReadLine()) != null )
    Console.WriteLine( curLine );
最后關(guān)閉 StreamReader 對(duì)象:

sr.Close();
注意這樣將自動(dòng)地在底層 Stream 對(duì)象上調(diào)用 Close (),所以不必顯示地執(zhí)行 fs.Close()。

 

11.1.2 如何寫(xiě)文本文件?
和讀文件的例子相似,只是把 StreamReader 換成 StreamWriter。

 

11.1.3 如何讀寫(xiě)二進(jìn)制文件?
和文本文件類似,只是要用 BinaryReader/Writer 對(duì)象而不是 StreamReader/Writer 來(lái)包裝 FileStream 對(duì)象。

 

11.1.4 如何刪除文件?
在 System.IO.File 對(duì)象上使用靜態(tài)方法 Delete ():

File.Delete( @"c:/test.txt" );
 

11.2 文本處理
11.2.1 是否支持正規(guī)表達(dá)式?
是的。使用 System.Text.RegularExpressions.Regex 類。例如,以下代碼更新 HTML 文件的標(biāo)題:

FileStream fs = new FileStream( "test.htm", FileMode.Open, FileAccess.Read );
StreamReader sr = new StreamReader( fs );

Regex r = new Regex( "<TITLE>(.*)</TITLE>" );
string s;
while( (s = sr.ReadLine()) != null )
{
    if( r.IsMatch( s ) )
        s = r.Replace( s, "<TITLE>New and improved ${1}</TITLE>" );
    Console.WriteLine( s );
}
 

11.3 Internet
11.3.1 如何下載網(wǎng)頁(yè)?
首先使用 System.Net.WebRequestFactory 類來(lái)獲得一個(gè) WebRequest 對(duì)象:

WebRequest request = WebRequestFactory.Create( "http://localhost" );
然后請(qǐng)求應(yīng)答:

WebResponse response = request.GetResponse();
GetResponse 方法被阻塞直到下載完成。然后你能像下面那樣訪問(wèn)應(yīng)答流:

Stream s = response.GetResponseStream();

// Output the downloaded stream to the console
StreamReader sr = new StreamReader( s );
string line;
while( (line = sr.ReadLine()) != null )
    Console.WriteLine( line );
注意 WebRequest 和 WebReponse 對(duì)象分別向下兼容 HttpWebRequest 和 HttpWebReponse 對(duì)象,它們被用來(lái)訪問(wèn)和 http 相關(guān)的功能。

 

11.3.2 如何使用代理服務(wù)器 (proxy)?
兩種—這樣做以便影響所有 Web 請(qǐng)求:

System.Net.GlobalProxySelection.Select = new DefaultControlObject( "proxyname", 80 );
另外一種,要想對(duì)特定的 Web 請(qǐng)求設(shè)置代理服務(wù),這樣做:

ProxyData proxyData = new ProxyData();
proxyData.HostName = "proxyname";
proxyData.Port = 80;
proxyData.OverrideSelectProxy = true;

HttpWebRequest request = (HttpWebRequest)WebRequestFactory.Create( "http://localhost" );
request.Proxy = proxyData;
 

11.4 XML
11.4.1 是否支持 DOM?
是的。看看以下示例 XML文檔:

<PEOPLE>
    <PERSON>Fred</PERSON>
    <PERSON>Bill</PERSON>   
</PEOPLE>   
可以這樣處理此文檔:

XmlDocument doc = new XmlDocument();
doc.Load( "test.xml" );

XmlNode root = doc.DocumentElement;

foreach( XmlNode personElement in root.ChildNodes )
    Console.WriteLine( personElement.FirstChild.Value.ToString() );
輸出為:

Fred
Bill
 

11.4.2 是否支持 SAX?
不。作為替換,提供了一個(gè)新的 XmlReader/XmlWriter API。像 SAX 一樣,它是基于流的,但它使用“pull”模型而不是 SAX 的“push”模型。這是一個(gè)例子:

XmlTextReader reader = new XmlTextReader( "test.xml" );

while( reader.Read() )
{
    if( reader.NodeType == XmlNodeType.Element && reader.Name == "PERSON" )
    {
        reader.Read(); // Skip to the child text
        Console.WriteLine( reader.Value );
    }
}
 

11.4.3 是否支持 XPath?
是的,通過(guò) XmlNavigator 類 (DocumentNavigator 是從 XmlNavigator 導(dǎo)出的):

XmlDocument doc = new XmlDocument();
doc.Load( "test.xml" );

DocumentNavigator nav = new DocumentNavigator(doc);
nav.MoveToDocument();

nav.Select( "descendant::PEOPLE/PERSON" );

while( nav.MoveToNextSelected() )
{
    nav.MoveToFirstChild();
    Console.WriteLine( "{0}", nav.Value );
}
 

11.5 線程
11.5.1 是否支持多線程?
是的,對(duì)多線程有廣泛的支持。系統(tǒng)能產(chǎn)生新線程,并提供應(yīng)用程序可以使用的線程池。

 

11.5.2 如何產(chǎn)生一個(gè)線程?
創(chuàng)建 System.Threading.Thread 對(duì)象的一個(gè)實(shí)例,把將要在新線程中執(zhí)行的 ThreadStart 示例傳遞給它。例如:

class MyThread
{
    public MyThread( string initData )
    {
        m_data = initData;
        m_thread = new Thread( new ThreadStart(ThreadMain) );
        m_thread.Start();
    }

    // ThreadMain() is executed on the new thread.
    private void ThreadMain()
    {
        Console.WriteLine( m_data );
    }

    public void WaitUntilFinished()
    {
        m_thread.Join();
    }

    private Thread m_thread;
    private string m_data;
}
這里創(chuàng)建 MyThread 的一個(gè)實(shí)例就足以產(chǎn)生線程并執(zhí)行 MyThread.ThreadMain () 方法:

MyThread t = new MyThread( "Hello, world." );
t.WaitUntilFinished();
 

11.5.3 如何停止一個(gè)線程?
有好幾個(gè)辦法。首先,你能使用自己的通訊機(jī)制告訴 ThreadStart 方法結(jié)束。另外 Thread 類有內(nèi)置的支持來(lái)命令線程停止。基本的兩個(gè)方法是 Thread.Interrupt () 和 Thread.Abort ()。前者導(dǎo)致拋出一個(gè) ThreadInterruptedException 并隨后進(jìn)入 WaitJoinSleep 狀態(tài)。換句話說(shuō),Thread.Interrupt 是一種禮貌的方式,它請(qǐng)求線程在不再進(jìn)行任何有用的工作時(shí)自行停止的。與此相對(duì)應(yīng),Thread.Abort () 拋出一個(gè) ThreadAbortException 而不管線程正在做什么。而且,ThreadAbortException 不能像通常的異常那樣被捕獲 (即使最終將執(zhí)行 ThreadStart 的終止方法)。Thread.Abort () 是一般情況下不需要的非常手段。

 

11.5.4 怎樣使用線程池?
通過(guò)向 ThreadPool.QueueUserWorkItem () 方法傳遞 WaitCallback 的一個(gè)實(shí)例:

class CApp
{
    static void Main()
    {
        string s = "Hello, World";
        ThreadPool.QueueUserWorkItem( new WaitCallback( DoWork ), s );

        Thread.Sleep( 1000 );    // Give time for work item to be executed
    }

    // DoWork is executed on a thread from the thread pool.
    static void DoWork( object state )
    {
        Console.WriteLine( state );
    }
}
 

11.5.5 怎樣知道我的線程池工作項(xiàng)目是在何時(shí)完成的?
沒(méi)有方法詢問(wèn)線程池這類信息。你必須在 WaitCallback 方法中放置代碼來(lái)發(fā)出信號(hào)以表明它已經(jīng)完成。這里事件也很有用處。

 

11.5.6 怎樣防止對(duì)數(shù)據(jù)的并發(fā)訪問(wèn)?
每個(gè)對(duì)象有一個(gè)與之相聯(lián)的并發(fā)鎖 (受批評(píng)的部分)。System.Threading.Monitor.Enter/Exit 方法用來(lái)獲得和釋放鎖。例如,下面類的實(shí)例只允許一個(gè)線程同時(shí)進(jìn)入方法 f ():

class C
{
    public void f()
    {
        try
        {
            Monitor.Enter(this);
            ...
        }
        finally
        {
            Monitor.Exit(this);
        }
    }
}
C# 有一個(gè)關(guān)鍵字‘lock’提供了以上代碼的簡(jiǎn)單形式:

class C
{
    public void f()
    {
        lock(this)
        {
            ...
        }
    }
}
注意,調(diào)用 Monitor.Enter (myObject) 并不意味著對(duì) myObject 的所有訪問(wèn)都被串行化了。它意味著請(qǐng)求同 myObject 相聯(lián)的同步鎖,并且在調(diào)用 Monitor.Exit(o) 之前,沒(méi)有任何其它線程可以請(qǐng)求該鎖。換句話說(shuō),下面的類和以上給出的類在功能上是等同的:

class C
{
    public void f()
    {
        lock( m_object )
        {
            ...
        }
    }

    private m_object = new object();
}
 

11.6 跟蹤
11.6.1 有內(nèi)置的跟蹤/日志支持嗎?
是的,在 System.Diagnostics 命名空間中。有兩個(gè)處理跟蹤的主要的類—Debug 和 Trace。它們以相似的方式工作—不同之處是 Debug 類中的跟蹤只能在用 DEBUG 標(biāo)志生成的代碼中工作,而 Trace 類中的跟蹤只能在指明了 TRACE 標(biāo)記生成的代碼中工作。典型地,這意味著你應(yīng)該在你希望能在 debug 和 release 版本中都能跟蹤時(shí)使用 System.Diagnostics.Trace.WriteLine,而在你希望只能在 debug 版本中能跟蹤時(shí)使用 System.Diagnostics.Debug.WriteLine。

 

11.6.2 能否將跟蹤輸出重定向到一個(gè)文件?
是的。Debug 類和 Trace 類都有一個(gè) Listeners 屬性,它們分別收集你用 Debug.WriteLine 或 Trace.WriteLine 產(chǎn)生的輸出。默認(rèn)情況下 Listeners 只有一個(gè)收集槽,它是 DefaultTraceListener 類的一個(gè)實(shí)例。它將輸出發(fā)送到 Win32 的 OutputDebugString () 函數(shù)和 System.Diagnostics.Debugger.Log () 方法。調(diào)試時(shí)這很有用,但如果你試圖從客戶站點(diǎn)跟蹤一個(gè)問(wèn)題,將輸出重定向到一個(gè)文件中就更為恰當(dāng)。幸運(yùn)的是,為此目的提供了 TextWriterTraceListener 類。

這里是 TextWriterTraceListener 如何將 Trace 輸出重定向到一個(gè)文件:

Trace.Listeners.Clear();
FileStream fs = new FileStream( @"c:/log.txt", FileMode.Create, FileAccess.Write );
Trace.Listeners.Add( new TextWriterTraceListener( fs ) );

Trace.WriteLine( @"This will be writen to c:/log.txt!" );
注意使用 Trace.Listeners.Clear () 去掉了默認(rèn)的 listener。如果不這樣做,輸出將在文件和 OutputDebugString () 中同時(shí)產(chǎn)生。一般情況下你不希望如此,因?yàn)?OutputDebugString () 導(dǎo)致很大的性能開(kāi)銷。

 

11.6.3 能否定制跟蹤的輸出?
是的。你能編寫(xiě)你自己的 TraceListener 導(dǎo)出類,并把所有的輸出重定向到它上面。這里有一個(gè)簡(jiǎn)單的例子,它從 TextWriterTraceListener 導(dǎo)出 (并隨后內(nèi)建了對(duì)寫(xiě)文件的支持) 并在每個(gè)輸出行上添加時(shí)間信息和線程 ID:

class MyListener : TextWriterTraceListener
{
    public MyListener( Stream s ) : base(s)
    {
    }

    public override void WriteLine( string s )
    {
        Writer.WriteLine( "{0:D8} [{1:D4}] {2}",
            Environment.TickCount - m_startTickCount,
            AppDomain.GetCurrentThreadId(),
            s );
    }

    protected int m_startTickCount = Environment.TickCount;
}
(注意這個(gè)實(shí)現(xiàn)并不完整—例如沒(méi)有覆蓋 TraceListener.Write 方法。)

這種方法的美妙之處在于,向 Trace.Listener 添加 MyListener 之后,所有對(duì) Trace.WriteLine () 的調(diào)用都轉(zhuǎn)向了 MyListener,包括從對(duì) MyListener 一無(wú)所知的被引用元件發(fā)出的調(diào)用。

 

12. 資源
12.1 從哪里可以獲得關(guān)于 .NET 的詳情?
Microsoft .NET 主頁(yè)位于 http://www.microsoft.com/net/。Microsoft 同時(shí)將它發(fā)布在 GOTDOTNET。

Microsoft 還發(fā)布了 .NET Framework FAQ,和本文很相似。可以在那里找到這里許多問(wèn)題更“權(quán)威”的解答。

Robert Scoble 編輯了一個(gè)很容易理解的在線列表 http://www.devx.com/dotnet/resources/,這里還有一個(gè) http://www.singularidad.com.ar/dotnet.asp

http://www.devx.com/free/press/2000/vs-qalist.asp Robert 還有一個(gè) .NET“著名問(wèn)題與解答”主頁(yè)。

Richard Grimes 和 Richard Anderson 有一個(gè)叫作 Managed World.COM.的站點(diǎn)。

http://www.ibuyspy.com/ 是一個(gè)以展示 .NET 平臺(tái)為目的創(chuàng)建的示例站點(diǎn)。

還有我的 C# FAQ for C++ Programmers。

 

12.2 示例代碼和實(shí)用程序
Peter Drayton 的 .NET Goodies 主頁(yè)位于 http://www.razorsoft.net/
Don Box 的 CallThreshold 示例位于 http://www.develop.com/dbox/dotnet/threshold
Don 的 UnwindScope Service 位于 http://www.develop.com/dbox/dotnet/unwind
Don 的 CLR scripting host 位于 http://www.develop.com/dbox/dotnet/clrscript
Don 和 Jason 的 dm.net COM moniker 位于 http://staff.develop.com/jasonw/clr/readme.htmhttp://www.bearcanyon.com/dotnet/ 有 Mike Woodring 的一些 .NET 例子。
http://www.cookcomputing.com/xmlrpc/xmlrpc.shtml 可以找到 Charles Cook 的 XML-RPC.Net library。

 

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 浦城县| 保亭| 巴青县| 福海县| 商城县| 星子县| 玉门市| 婺源县| 陇南市| 龙南县| 泗水县| 遂平县| 蒲城县| 云南省| 崇文区| 介休市| 吴忠市| 宁南县| 栾川县| 福海县| 横峰县| 宝山区| 海南省| 琼结县| 礼泉县| 游戏| 梓潼县| 盐池县| 富民县| 连城县| 祥云县| 岳普湖县| 西乌| 武清区| 渭南市| 喀什市| 黄骅市| 巴林右旗| 博乐市| 麦盖提县| 游戏|