二級輔導(dǎo):由C++轉(zhuǎn)向C#需要注意的變化(五)

字號:

屬性的使用
    為了對屬性進(jìn)行測試,我們創(chuàng)建一個(gè)名字為MyMath的簡單類,并給它添加二個(gè)函數(shù),然后給它指定bugfix屬性。
    [BugFixAttribute(121,"JesseLiberty","01/03/05")]
    [BugFixAttribute(107,"JesseLiberty","01/04/05",
    Comment="Fixedoffbyoneerrors")]
    publicclassMyMath
    這些數(shù)據(jù)將與元數(shù)據(jù)存儲在一起。下面是完整的源代碼及其輸出:
    自定義屬性
    usingSystem;
    //創(chuàng)建被指派給類成員的自定義屬性
    [AttributeUsage(AttributeTargets.Class,
    AllowMultiple=true)]
    publicclassBugFixAttribute:System.Attribute
    {
    //位置參數(shù)的自定義屬性構(gòu)造器
    publicBugFixAttribute
    (intbugID,
    stringprogrammer,
    stringdate)
    {
    this.bugID=bugID;
    this.programmer=programmer;
    this.date=date;
    }
    publicintBugID
    {
    get
    {
    returnbugID;
    }
    }
    //命名參數(shù)的屬性
    publicstringComment
    {
    get
    {
    returncomment;
    }
    set
    {
    comment=value;
    }
    }
    publicstringDate
    {
    get
    {
    returndate;
    }
    }
    publicstringProgrammer
    {
    get
    {
    returnprogrammer;
    }
    }
    //專有成員數(shù)據(jù)
    privateintbugID;
    privatestringcomment;
    privatestringdate;
    privatestringprogrammer;
    }
    //把屬性指派給類
    [BugFixAttribute(121,"JesseLiberty","01/03/05")]
    [BugFixAttribute(107,"JesseLiberty","01/04/05",
    Comment="Fixedoffbyoneerrors")]
    publicclassMyMath
    {
    publicdoubleDoFunc1(doubleparam1)
    {
    returnparam1+DoFunc2(param1);
    }
    publicdoubleDoFunc2(doubleparam1)
    {
    returnparam1/3;
    }
    }
    publicclassTester
    {
    publicstaticvoidMain()
    {
    MyMathmm=newMyMath();
    Console.WriteLine("CallingDoFunc(7).Result:{0}",
    mm.DoFunc1(7));
    }
    }
    輸出:
    CallingDoFunc(7).Result:9.3333333333333339
    象我們看到的那樣,屬性對輸出絕對沒有影響,創(chuàng)建屬性也不會影響代碼的性能。到目前為止,讀者也只是在聽我論述有關(guān)屬性的問題,使用ILDASM瀏覽元數(shù)據(jù),就會發(fā)現(xiàn)屬性確實(shí)是存在的。
    映射
    在許多情況下,我們需要一種方法,能夠從元數(shù)據(jù)中訪問屬性,C#提供了對映射的支持以訪問元數(shù)據(jù)。通過初始化MemberInfo類型對象,System.Reflection名字空間中的這個(gè)對象可以用來發(fā)現(xiàn)成員的屬性,對元數(shù)據(jù)進(jìn)行訪問。
    System.Reflection.MemberInfoinf=typeof(MyMath);
    對MyMath類型調(diào)用typeof操作符,它返回一個(gè)由繼承MemberInfo而生成的Type類型的變量。
    下一步是對MemberInfo對象調(diào)用GetCustomAttributes,并將希望得到的屬性的類型作為一個(gè)參數(shù)傳遞給GetCustomAttributes??荚嚧筇崾緦⒌玫揭粋€(gè)對象數(shù)組,數(shù)組的每個(gè)成員的類型都是BugFixAttribute。
    object[]attributes;
    attributes=Attribute.GetCustomAttributes(inf,typeof(BugFixAttribute));我們就可以遍歷這個(gè)數(shù)組了,打印BugFixAttribute對象的數(shù)組,代碼下所示:
    屬性的打印
    publicstaticvoidMain()
    {
    MyMathmm=newMyMath();
    Console.WriteLine("CallingDoFunc(7).Result:{0}",
    mm.DoFunc1(7));
    //獲取成員信息并使用它訪問自定義的屬性
    System.Reflection.MemberInfoinf=typeof(MyMath);
    object[]attributes;
    attributes=
    Attribute.GetCustomAttributes(inf,typeof(BugFixAttribute));
    //遍歷所有的屬性
    foreach(Objectattributeinattributes)
    {
    BugFixAttributebfa=(BugFixAttribute)attribute;
    Console.WriteLine("\nBugID:{0}",bfa.BugID);
    Console.WriteLine("Programmer:{0}",bfa.Programmer);
    Console.WriteLine("Date:{0}",bfa.Date);
    Console.WriteLine("Comment:{0}",bfa.Comment);
    }
    }
    類型發(fā)現(xiàn)
    我們可以通過映象的方法來研究一個(gè)組合實(shí)體的內(nèi)容,如果要建立需要顯示組合體內(nèi)部信息的工具或動(dòng)態(tài)地調(diào)用組合體中的途徑,這一方法是非常有用的。
    通過映象的方法,我們可以知道一個(gè)模塊、方法、域、屬性的類型,以及該類型的每個(gè)方法的信號、該類支持的界面和該類的超級類。我們可以通過如下的形式,用Assembly.Load靜態(tài)方法動(dòng)態(tài)地加載一個(gè)組合體:
    publicstaticAssembly.Load(AssemblyName)
    然后,可以將它傳遞到核心庫中。
    Assemblya=Assembly.Load("Mscorlib.dll");
    一旦加載了組合體,我們可以通過調(diào)用GetTypes返回一個(gè)Type對象數(shù)組。Type對象是映射的核心,它表示類、界面、數(shù)組、值和枚舉等的類型定義。
    Type[]types=a.GetTypes();
    組合休會返回一個(gè)類型的數(shù)組,我們可以使用foreach-loop結(jié)構(gòu)顯示該數(shù)組,其輸出將有好幾頁文檔之多,下面我們從中找一小段:
    TypeisSystem.TypeCode
    TypeisSystem.Security.Util.StringExpressionSet
    TypeisSystem.Text.UTF7Encoding$Encoder
    TypeisSystem.ArgIterator
    TypeisSystem.Runtime.Remoting.JITLookupTable
    1205typesfound
    我們得到了一個(gè)內(nèi)容為核心庫中類型的數(shù)組,可以將它們都打印出來,該數(shù)組將有1205個(gè)項(xiàng)。
    對一種類型映射我們也可以對組合體中一種類型進(jìn)行映射。為此,我們可以使用GetType方法從組合體中解析出一個(gè)類型:
    publicclassTester
    {
    publicstaticvoidMain()
    {
    //檢查一個(gè)對象
    TypetheType=Type.GetType("System.Reflection.Assembly");
    Console.WriteLine("\nSingleTypeis{0}\n",theType);
    }
    }
    輸出如下所示:
    SingleTypeisSystem.Reflection.Assembly
    發(fā)現(xiàn)成員
    我們還可以得到所有成員的類型,顯示所有的方法、屬性、域,下面的代碼演示了實(shí)現(xiàn)上述目標(biāo)的代碼。
    Figure9GettingAllMembers
    publicclassTester
    {
    publicstaticvoidMain()
    {
    //檢查一個(gè)單一的對象
    TypetheType=Type.GetType("System.Reflection.Assembly");
    Console.WriteLine("\nSingleTypeis{0}\n",theType);
    //獲取所有的成員
    MemberInfo[]mbrInfoArray=
    theType.GetMembers(BindingFlags.LookupAll);
    foreach(MemberInfombrInfoinmbrInfoArray)
    {
    Console.WriteLine("{0}isa{1}",
    mbrInfo,mbrInfo.MemberType.Format());
    }
    }
    }
    盡管得到的輸出還非常長,但在輸出中我們可以得到如下面的不甘落后民示的域、方法、構(gòu)造器和屬性:
    System.Strings_localFilePrefixisaField
    BooleanIsDefined(System.Type)isaMethod
    Void.ctor()isaConstructor
    System.StringCodeBaseisaProperty
    System.StringCopiedCodeBaseisaProperty