考慮如下測試代碼的一般的做法。程序加載指定的程序集,得到一個包含程序集中所有成員的數組,在它們中間,迭代尋找應用了[DefectTrack]特性的類。對於應用了[DefectTrack]特性的類,測試程序將在控制台上輸出特性的值。對於類型中的方法,程序仍然采用了同樣的步驟和迭代。這些循環采用它們的方式在整個程序集裡“游走”。
using System ; using System.Reflection ; using MyAttributeClasses ; public class TestMyAttribute { public static void Main( ) { DisplayDefectTrack( "MyAttributes" ) ; Console.ReadLine(); } public static void DisplayDefectTrack( string lcAssembly ) { Assembly loAssembly = Assembly.Load( lcAssembly ) ; Type[ ] laTypes = loAssembly.GetTypes( ) ; foreach( Type loType in laTypes ) { Console.WriteLine("*======================*" ) ; Console.WriteLine( "TYPE:\t" + loType.ToString( ) ) ; Console.WriteLine( "*=====================*" ) ; object[ ] laAttributes = loType.GetCustomAttributes( typeof( DefectTrackAttribute ), false ) ; if( laAttributes.Length > 0 ) Console.WriteLine( "\nMod/Fix Log:" ) ; foreach( Attribute loAtt in laAttributes ) { DefectTrackAttribute loDefectTrack = (DefectTrackAttribute)loAtt ; Console.WriteLine( "----------------------" ) ; Console.WriteLine( "Defect ID:\t" + loDefectTrack.DefectID ) ; Console.WriteLine( "Date:\t\t" + loDefectTrack.ModificationDate ) ; Console.WriteLine( "Developer ID:\t" + loDefectTrack.DeveloperID ) ; Console.WriteLine( "Origin:\t\t" + loDefectTrack.Origin ) ; Console.WriteLine( "Comment:\n" + loDefectTrack.FixComment ) ; } MethodInfo[ ] laMethods = loType.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) ; if( laMethods.Length > 0 ) { Console.WriteLine( "\nMethods: " ) ; Console.WriteLine( "----------------------" ) ; } foreach( MethodInfo loMethod in laMethods ) { Console.WriteLine( "\n\t" + loMethod.ToString( ) ) ; object[ ] laMethodAttributes = loMethod.GetCustomAttributes( typeof( DefectTrackAttribute ), false ) ; if( laMethodAttributes.Length > 0 ) Console.WriteLine( "\n\t\tMod/Fix Log:" ) ; foreach( Attribute loAtt in laMethodAttributes ) { DefectTrackAttribute loDefectTrack = (DefectTrackAttribute)loAtt ; Console.WriteLine( "\t\t----------------" ) ; Console.WriteLine( "\t\tDefect ID:\t" + loDefectTrack.DefectID ) ; Console.WriteLine( "\t\tDeveloper ID:\t" + loDefectTrack.DeveloperID ) ; Console.WriteLine( "\t\tOrigin:\t\t" + loDefectTrack.Origin ) ; Console.WriteLine( "\t\tComment:\n\t\t" + loDefectTrack.FixComment ) ; } } Console.WriteLine( "\n\n" ) ; } } }
讓我們來看一下比較重要的幾行代碼。DisplayDefectTrack()方法的第一行代碼和第二行代碼得到了加載指定程序集的一個引用並且得到了包含在該程序集中類型的一個數組。
Assembly loAssembly =
Assembly.Load( lcAssembly ) ;
Type[ ] laTypes = loAssembly.GetTypes( ) ;
使用foreach語句在程序集中的每一個類型上迭代。在控制台上輸出當前類型的名稱,並使用如下的語句查詢當前類型,獲取有關[DefectTrack]特性的一個數組。
object[ ] laAttributes =
loType.GetCustomAttributes(
typeof( DefectTrackAttribute ),
false ) ;
你需要在GetCustomAttributes方法上指定typeof(DefectTrackAttribute) 參數,以限制僅僅返回你創建的自定義特性。第二個參數false指定是否搜索該成員的繼承鏈以查找這些自定義特性。
使用foreach語句迭代自定義特性數組,並把它們(自定義特性)的值輸出到控制台上。你應該認識到第一個foreach語句塊會創建一個新的變量,並且對當前的特性作類型轉化。
DefectTrackAttribute loDefectTrack =
(DefectTrackAttribute)loAtt ;
這一條語句為什麼是必須的呢?GetCustomAttributes()方法會返回一個object數組,你為了訪問自定義特性的值,所以必須把這些引用轉化為它們真正的具體類的引用。轉化完以後,你就可以使用這些特性並且可以把特性的值輸出到控制台上。
因為你可以在任意的類和方法上應用特性,因此程序需要調用當前類型上的方法GetMethods()。
MethodInfo[ ] laMethods =
loType.GetMethods(
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly ) ;
在這個例子裡,我給GetMethods()方法傳遞了一些BindingFlags枚舉值。組合使用這三個枚舉值,限制僅僅返回在當前的類中直接定義的方法。在這個例子裡,之所以這樣做,是因為我想限制輸出的數量,但是在實際當中,你可能並不需要這樣做,因為開發人員可能會在一個重寫的方法上應用[DefectTrack]特性。而我的實現代碼並沒有捕捉應用在這些方法上的特性。
剩下的代碼,從本質上來說,對每一個方法以及每一個類,都在做相同的操作。都是在每一個方法上尋找是否應用了[DefectTrack]特性,如果應用了,就把特性的值輸出到控制台上。
總結
在這裡,我只是利用一個簡單的例子,介紹了開發者如何使用.Net特性提高開發進程。自定義特性有點類似於XML,它最大的好處不在於“它做了什麼”,它真正最大的好處在於“你可以用它做什麼”。這個是真正無止境的,由於自定義特性本身具有開放的特性,這使得它可以擁有更多新穎的用途。