六月婷婷综合激情-六月婷婷综合-六月婷婷在线观看-六月婷婷在线-亚洲黄色在线网站-亚洲黄色在线观看网站

明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

ASP.NET技術FAQ

[摘要]1. 簡介 1.1 什么是 .NET? 1.2 .NET 只是 Windows DNA 的一個新名字嗎? 1.3 .NET 只適用于建立 Web 網站嗎? 1.4 .NET 是在什么時候宣布的? 1.5 .NET 將在何時發布? 1.6 如何開發 .NET 應用程序 1.7 可以從哪里下載 .NE...

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

1. 簡介
1.1 什么是 .NET?
很難用一句話來講清楚。根據 Microsoft 的說法,.NET 是一個“革命性的新平臺,建立在開放的 Internet 協議和標準之上,通過工具和服務將計算和通訊以嶄新的方式融合到一起” 。

更為實際的定義是:.NET 是一個開發和運行軟件的新環境,便于開發基于 Web 的服務,擁有豐富的運行庫服務以支持用多種編程語言編寫的組件,具有跨語言和跨平臺的互操作能力。

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

 

1.2 .NET 只是 Windows DNA 的一個新名字嗎?
不。在很多地方,Windows DNA 僅僅是指使用現有技術的一種途徑(即所謂的三階式途徑)的市場術語。.NET 更為急進,并且包括一個完整的軟件開發和運行庫框架。

 

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

 

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

 

1.5 .NET 將在何時發布?
預計是在 2001 年的下半年。

 

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

 

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 中的關鍵技術是什么?
ASP.NET、CLR (Common Language Runtime—通用語言運行庫)、C# (新一代的類-Java 語言)、SOAP、XML、ADO.NET、多語言支持 (Eiffel、COBOL 等等)

 

1.9 .NET 框架將運行在什么平臺上?
Beta 1 支持在 Windows 2000、NT4 SP6a, Windows Me 和 Windows 98 上進行開發。Windows 95 支持運行庫。

Microsoft 將按照和 .NET 運行庫相似的時間表發布一個新版本 Windows。它的代號是“Whistler”,在很大程度上是對 Windows 2000 的擴充性更新,對 GUI 有重要的改變。Microsoft 將以“.NET-enabled”作為新操作系統的賣點,但看起來它沒有和 .NET 運行庫綁在一起。如果 .NET 運行庫能及時完成,它將包含在 Whistler 之內;否則,Whistler 將單獨發貨。

 

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

 

1.11 .NET 框架符合標準化趨勢嗎?
C# 以及稱為“通用語言基礎結構”的一些東西的推薦標準草案已經提交給了 ECMA。參見 http://msdn.microsoft.com/net/ecma/

 

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

面向對象的編程模型 (繼承、多態、異常處理、垃圾收集)
安全模型
類型系統
所有的 .NET 基礎類
許多 .NET 框架類
開發、調試和測評工具
運行和代碼管理
IL-機器語言 轉換器和優化器

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

 

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

 

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

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

 

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

 

2.5 什么是 C#?
C# 是在 .NET 框架中運行的一種新語言。在他們的“C# 簡介”白皮書中,Microsoft 這樣描述 C#:

“C# 是從 C 和 C++ 派生出來的一種簡單的、面向對象的、并且是類型安全的現代編程語言。C# (發音為‘C sharp’) 牢固地根植于在 C 和 C++ 家族之樹,將很快為 C 和 C++ 程序員所熟悉。C# 幫助開發者將 Visual Basic 的高生產率和 C++ 的直接控制能力結合起來。”

將以上引言中的“C#”換成“Java”,你會發現這句陳述依然很正確 :)。

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

 

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

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

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

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

 

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

使用映像來訪問 .NET 的特殊數據同使用 ITypeLib/ITypeInfo 來訪問 COM 中的類型庫數據非常相似,而且使用的目的也很相似—例如確定數據類型大小,以便在上下文、進程、機器的邊界間調度它們。

映像還可以被用來動態調用方法 (參見 System.Type.InvokeMember),甚至在運行時動態創建類型 (參見 System.Reflection.Emit.TypeBuilder )。

 

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

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

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

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

 

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

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

csc /t:library ctest.cs
通過運行 .NET SDK 所帶的“IL 反匯編”工具,你能看到元件的內容。

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

 

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

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

 

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

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

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

 

4. 應用程序域
4.1 什么是應用程序域?
應用程序域 (AppDomain) 可以被看作一個輕型的進程。在一個 Win32 進程中可以存在多個 AppDomain。AppDomain 的主要目的是將應用程序和其它應用程序隔離開來。

通過使用獨立的地址空間,Win32 進程提供隔離性。這種方法很有效,但開銷很大并且伸縮性不好。.NET 運行庫通過控制對內存的是用來施加 AppDomain 隔離—AppDomain 中的所有內存是由 .NET 運行庫來管理的,所以運行庫可以確保 AppDomain 之間不能訪問彼此的內存。

 

4.2 如何創建 AppDomain?
AppDomains 通常有宿主創建。宿主包括 Windows Shell、ASP+ 和 IE。當你從命令行運行一個 .NET 應用程序時,宿主是 Shell。Shell 為每個應用程序創建一個新的 AppDomain。

AppDomains 也可以由 .NET 應用程序來顯式創建。這里是一個創建 AppDomain 的一個 C# 例子,它創建對象的一個實例,并隨后執行對象的一個方法:

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 我能編寫自己的 .NET 宿主嗎?
能。關于怎樣來做的例子,看看 Jason Whittington 和 Don Box 開發的 dm.net moniker 的源代碼 (http://staff.develop.com/jasonw/clr/readme.htm)。在 .NET SDK 中也有一個叫作 CorHost 的代碼示例。

 

5. 垃圾收集
5.1 什么是垃圾收集?
垃圾收集是一個系統,運行庫組件通過它來管理對象的生存周期和它們占用的堆內存。對 .NET 而言它并不是一個新概念—Java 和許多其它語言/運行庫使用垃圾收集已經有一段時間了。

 

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

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

2000 年 10 月,Microsoft 的 Brian Harry 貼出了一個針對這個問題的很長的分析:http://discuss.develop.com/archives/wa.exe?A2=ind0010A&L=DOTNET&P=R28572

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

 

5.3 .NET 為什么不提供確定化的析構?
因為垃圾收集算法。.NET 的垃圾收集器通過周期地掃描應用程序正在使用的所有對象的列表來工作。掃描過程中所有未被發現的對象就可以被銷毀并釋放內存。當對對象的最后一個引用撤銷后,算法的這種實現使運行庫不能立即得到通知—它只能在下一次清理堆時發現。

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

 

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

 

5.5 確定化的析構是否影響在被管理代碼中使用 COM 對象?
是的。從被管理代碼中使用 COM 對象時,你實際上是依賴垃圾收集器來最終釋放你的對象。如果你的 COM 對象占有昂貴的資源且只能在最終釋放對象后才能釋放,你可能需要在你的對象上提供一個新接口以支持顯式的 Dispose () 方法。

 

5.6 我聽說應該避免使用 Finalize 方法,那么是否應該在我的類理實現 Finalize?
對垃圾收集器而言,擁有 Finalize 方法的對象比沒有此方法的對象需要做更多的工作。同時也不保證對象 Finalized 的次序,所以對于從 Finalized 方法訪問其它對象有不同的看法。最后,不能保證 Finalized 方法一定能被調用。所以,永遠不應該依賴它來清理對象的資源。

Microsoft 建議使用以下方式:

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

 

5.7 我有控制垃圾收集算法的手段嗎?
有一點。System.GC 類提供了一對有趣的方法。第一個是 Collect 方法—它強制垃圾收集器立即收集所有未被引用的對象。另一個是 RequestFinalizeOnShutdown (),它告訴垃圾收集器在應用程序關閉時一定要對每個對象運行 Finalize () 方法。在應用程序關閉時,垃圾收集器一般優先選擇快速的推出方式而不是調用 Finzlize (),所以這個方法能手工強制運行庫多負一點責任。

如果你想驗證這不僅僅是理論上的說法,是一十下面的測試程序:

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();
    }
}
運行此程序,然后再去掉 GC.RequestFinalizeOnShutdown() 這一行前面的注釋標記并重新運行,注意有什么不同……

 

5.8 我怎么知道垃圾收集器在做什么?
.NET 運行庫中很多令人感興趣的統計通過 'COM+ Memory' 性能對象輸出。使用 Performance Monitor 查看它們。

 

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

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

 

6.2 我能創建自己的 metadata 屬性嗎?
是的。簡單地從 System.Attribute 導出一個類并將其標記為 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 我能創建自己的 context 屬性嗎?
是的。看看 http://www.develop.com/dbox/dotnet/threshold/ 處的 Don Box 的例子 (叫作 CallThreshold) 和 http://www.razorsoft.net/ 處的 Perter Drayton 的 Tracehook.NET

 

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

 

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

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

 

7.3 誰定義 CAS 代碼組?
Microsoft 定義了一些默認代碼組,但你可以改變這些甚至創建你自己的代碼組。要想看到你的系統中定義的代碼組,可以從命令橫行運行“caspol -lg”命令。再我的系統里它看起來像這些:

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') 是最通用的,它隨后分為幾個組,每個還可以再分。同時注意,和一般的想象不同,子組可以被賦予比它的上級更寬的權限集。

 

7.4 如何定義自己的代碼組?
使用 caspol。例如,假定你信任來自 www.mydomain.com 的代碼,并且希望它對你的系統擁有完全的訪問權,但是希望對其它 Internet 站點保持默認的限制。要實現這些,你可以在“Zone - Internet”組中增加一個子組,就像下面那樣:

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

...
   1.3.  Zone - Internet: Internet
      1.3.1.  Site - www.mydomain.com: FullTrust
...
注意數字標號 (1.3.1) 只是 caspol 編出來以便能從命令行方便地操縱代碼組的。底層的運行庫永遠看不到它。

 

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

caspol -cg 1.2 FullTrust
注意,因為 (在標準的系統里) 這比默認的安全策略權限更大,你應該在 machine 層次上做這些—在 user 層次上這樣做不起作用。

 

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

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

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

 

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

 

7.8 我受不了 CAS 帶來的麻煩,能否關掉它?
是的,只要你是系統管理員。只要運行:

caspol -s off
 

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

 

8.2 能否通過反向工程從 IL 中獲得源代碼?
是的。相對而言,從 IL 來重新生成高級語言源代碼 (例如 C#) 通常是很簡單的。

 

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

不幸的事,目前的 .NET 編譯器沒有 /owner 選項,所以要想保護你的 C# 或 VB.NET 元件,你需要像下面那樣做:

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

看起來過一段時間能有 IL 加密工具 (無論來自 Microsoft 或第三方)。這些工具會以這樣的方式來“優化” IL:使反向工程變得更困難。

當然,如果你是在編寫 Web 服務,反向工程看起來就不再是一個問題,因為客戶不能訪問你的 IL。

 

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

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

 

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

 

9. 關于 COM
9.1 COM 消亡了嗎?
就像你在郵件列表中看到的那樣,這個主題導致了激烈的爭論。看看以下兩個地方:

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 包含很多內容,并且對于不同的人而言它是不同的東西。但是對我來說,COM 基本上是關于一小段代碼如何找到另一小段代碼,以及當它們相互找到后該如何相互通訊。COM 準確地指明了這種定位和通訊該如何進行。在完全由 .NET 對象構成的“純” .NET 世界里,小段代碼依然相互尋找并相互交談,但它們不使用 COM 來做這些。它們使用在某些地方和 COM 很相像的一種模型—例如,類型信息保存在和組件封裝在一起的表單中,這和在 COM 組件中封裝一個類型庫十分相似。但它不是 COM。

所以,這里有什么問題嗎?好吧,我確實不關心大多數 COM 消失了—我不關心尋找組件不再和注冊表有關,我也不使用 IDL 來定義我的借口。但有一件東西我不希望它消失—我不希望失去基于接口的開發這種思想。照我看來,COM 最強大的力量是它堅持在接口和實現之間豎起鑄鐵般的隔墻。不幸的是,看來 .NET 不再那樣堅持—它允許你做基于接口的開發,但它并不堅持。一些人可能會辯解說有一個選擇總不會是壞事,可能他們是對的,但我不能不覺得這可能是一個退步。

 

9.2 DCOM 消亡了嗎?
差不多是,尤其是對于 .NET 開發者。.NET 框架有一個不基于 DCOM 的新的遠程模型。當然 DCOM 還會在互操作場合下使用。

 

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

在一段時間內看來,互操作性可以預期是無縫集成的—這意味著一些服務將成為 CLR 的一部分,并且/或者意味著一些服務將以可管理代碼的形式重寫并運行在 CLR 的頂層。

關于這個主題,參見 Joe Long 的貼子—Joe 是 Microsoft 的 COM+ 組的經理。從這里開始:

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

 

9.4 能在 .NET 中使用 COM 組件嗎?
可以。可以通過 Runtime Callable Wrapper (RCW) 從 .NET 中訪問 COM 組件。它通過將 COM 組件映射為與 .NET 兼容的接口來使 COM 接口可以被訪問。對于 oldautomation 接口,可以自動地從一個類型庫中產生。對于非 oleautomation 接口,可以開發一個定制的 RCW,以便手工地將 COM 接口的類型映射為與 .NET 兼容的類型。

對于熟悉 ATL 的讀者,這里有一個簡單的示例。首先,創建一個 ATL 組件以實現以下 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;
    };
};
建立了組件以后,你會得到一個 typelibrary。在 typelibrary 上運行 TLBIMP 實用程序,就像這樣:

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

Typelib imported successfully to CPPCOMSERVERLib.dll
現在你需要一個 .NET 客戶端—我們用 C# 創建一個包含以下代碼的 .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 作為類名而且不需要語句 using CPPCOMSERVERLib。

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

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

現在你應該可以運行 csharpcomclient.exe,并從控制臺得到如下輸出:

Name is bob
 

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

這里是一個簡單的例子。創建一個名為 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
你會得到一個 dll,這樣將它注冊:

regasm testcomserver.dll /tlb:testcomserver.tlb
現在你需要創建一個客戶端程序來測試你的 .NET COM 組件。VBScript 可以—將以下內容放到一個名為 comclient.vbs 的文件中:

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

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

(注意,編寫此程序時,看起來可以通過幾種路徑將 .NET 類作為 COM 組件訪問—為了避免問題,在 testcomserver.dll 相同的目錄下運行 comclient.vbs。

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

 

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

 

10. 雜項
10.1 .NET 的遠程計算如何工作?
.NET 的遠程計算涉及通過通道發送消息。兩種標準的通道是 HTTP 和 TCP。僅僅在局域網上才傾向于使用 TCP—HTTP 能在局域網和廣域網 (internet) 上使用。

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

這里是遠程訪問的一些方式:

SingleCall。每個來自客戶端的請求由一個新對象服務。當請求完成后對象被丟棄。可以在 ASP+ 環境中使用 ASP+ 國家服務來保存應用程序或會話的國家,從而使這種模型 (無國家之分的) 變成有國家支持的。
 
Singleton。所有來在客戶端的請求由單一的服務器對象處理。
 
Client-activated object。這是老的有國家支持的 (D)COM 模型,這里客戶端受到一個遠端對象的引用并保留此引用 (以保持遠端對象的生存),直到對它的訪問完成。
對象的分布式垃圾收集由稱為“基于租用的生命周期”管理。每個對象擁有一個租用時間,這個時間到達時,從 .NET 運行庫的遠程子結構斷開對象。對象有默認的更新時間—從客戶端發起的成功調用會更新租用時間。客戶端也可以顯示地更新租用時間。

如果你對使用 XML-RPC 來代替 SOAP,可以看看 Charles Cook 在 http://www.cookcomputing.com/xmlrpc/xmlrpc.shtml 的 XML-RPC.Net 站點。

 

10.2 如何在 .NET 程序中獲得 Win32 API?
使用 P/Invoke。它使用了和 COM 互操作性相似的技術,但被用來訪問靜態 DLL 入口點而不是 COM 對象。以下是一個調用 Win32 MessageBox 函數的 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. 類庫
11.1 文件 I/O
11.1.1 如何讀文本文件?
首先,使用 System.IO.FileStream 對象打開文件:

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

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

sr.Close();
注意這樣將自動地在底層 Stream 對象上調用 Close (),所以不必顯示地執行 fs.Close()。

 

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

 

11.1.3 如何讀寫二進制文件?
和文本文件類似,只是要用 BinaryReader/Writer 對象而不是 StreamReader/Writer 來包裝 FileStream 對象。

 

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

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

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

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 如何下載網頁?
首先使用 System.Net.WebRequestFactory 類來獲得一個 WebRequest 對象:

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

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

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 對象分別向下兼容 HttpWebRequest 和 HttpWebReponse 對象,它們被用來訪問和 http 相關的功能。

 

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

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

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?
不。作為替換,提供了一個新的 XmlReader/XmlWriter API。像 SAX 一樣,它是基于流的,但它使用“pull”模型而不是 SAX 的“push”模型。這是一個例子:

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?
是的,通過 XmlNavigator 類 (DocumentNavigator 是從 XmlNavigator 導出的):

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 是否支持多線程?
是的,對多線程有廣泛的支持。系統能產生新線程,并提供應用程序可以使用的線程池。

 

11.5.2 如何產生一個線程?
創建 System.Threading.Thread 對象的一個實例,把將要在新線程中執行的 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;
}
這里創建 MyThread 的一個實例就足以產生線程并執行 MyThread.ThreadMain () 方法:

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

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

 

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

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 怎樣知道我的線程池工作項目是在何時完成的?
沒有方法詢問線程池這類信息。你必須在 WaitCallback 方法中放置代碼來發出信號以表明它已經完成。這里事件也很有用處。

 

11.5.6 怎樣防止對數據的并發訪問?
每個對象有一個與之相聯的并發鎖 (受批評的部分)。System.Threading.Monitor.Enter/Exit 方法用來獲得和釋放鎖。例如,下面類的實例只允許一個線程同時進入方法 f ():

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

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

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

    private m_object = new object();
}
 

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

 

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

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

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 () 去掉了默認的 listener。如果不這樣做,輸出將在文件和 OutputDebugString () 中同時產生。一般情況下你不希望如此,因為 OutputDebugString () 導致很大的性能開銷。

 

11.6.3 能否定制跟蹤的輸出?
是的。你能編寫你自己的 TraceListener 導出類,并把所有的輸出重定向到它上面。這里有一個簡單的例子,它從 TextWriterTraceListener 導出 (并隨后內建了對寫文件的支持) 并在每個輸出行上添加時間信息和線程 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;
}
(注意這個實現并不完整—例如沒有覆蓋 TraceListener.Write 方法。)

這種方法的美妙之處在于,向 Trace.Listener 添加 MyListener 之后,所有對 Trace.WriteLine () 的調用都轉向了 MyListener,包括從對 MyListener 一無所知的被引用元件發出的調用。

 

12. 資源
12.1 從哪里可以獲得關于 .NET 的詳情?
Microsoft .NET 主頁位于 http://www.microsoft.com/net/。Microsoft 同時將它發布在 GOTDOTNET。

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

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

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

Richard Grimes 和 Richard Anderson 有一個叫作 Managed World.COM.的站點。

http://www.ibuyspy.com/ 是一個以展示 .NET 平臺為目的創建的示例站點。

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

 

12.2 示例代碼和實用程序
Peter Drayton 的 .NET Goodies 主頁位于 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.htm 在 http://www.bearcanyon.com/dotnet/ 有 Mike Woodring 的一些 .NET 例子。
在 http://www.cookcomputing.com/xmlrpc/xmlrpc.shtml 可以找到 Charles Cook 的 XML-RPC.Net library。

 



標簽:ASP.NET技術FAQ 

相關文章

主站蜘蛛池模板: 四虎国产一区二区三区 | 四虎在线视频免费观看视频 | 天天插天天狠 | 青草欧美 | 欧美五月 | 亚洲成a人v欧美综合天堂软件 | 深爱五月婷婷 | 日本一本高清 | 日韩成人在线视频 | 人人免费人人专区 | 天天影视色香欲综合网天天录日日录 | 三级自拍视频 | 四虎国产精品永久地址49 | 青青青国产色视频在线观看 | 亚洲精品亚洲人成在线观看麻豆 | 伊人色在线 | 新一级毛片国语版 | 亚洲国产成人久久综合野外 | 日韩综合nv一区二区在线观看 | 亚洲国产精品久久久久666 | 日本一区二区视频免费播放 | 日日夜夜天天久久 | 日本中文字幕网 | 啪啪福利 | 欧美亚洲人成网站在线观看刚交 | 在线播放性xxx欧美 在线播放色 | 日本大学生免费一级一片 | 青青草免费在线观看 | 日韩精品手机在线 | 欧美太黄太色视频在线观看 | 午夜在线播放免费人成无 | 日韩a视频 | 欧美中文字幕视频 | 一级做a爰片久久毛片美女图片 | 天天躁夜夜躁狠狠躁躁 | 午夜激情在线 | 亚洲第99页| 五月婷婷六月丁香激情 | 最近韩国高清免费 hd | 手机av在线播放 | 亚洲最新网站 |