1、 在本章,你将学到:在本章,你将学到:创建自定义属性创建自定义属性使用反射抽取元数据使用反射抽取元数据 目标目标属性属性属性Propertyclass Employeeprivate static string _name;private static string _id;static void Main(string args)_name=Console.ReadLine();_id=Console.ReadLine();直接访问字段直接访问字段 不经验证不经验证 class Employee private static string _name;private static strin
2、g _id;public void SetId(value)/验证输入长度小于验证输入长度小于 2if(_id.Length 2)_id=value;public string GetId()return _id;方法方法 SetId(Value)和和 GetId()分别读取和写入职员分别读取和写入职员 ID Employee emp;emp.SetId(A1);string Department=emp.Get()每次都调用每次都调用 GetId()和和 SetId()方法会很繁琐方法会很繁琐属性class Employee private static string _name;priva
3、te static string _id;public string Id get return _id;set/验证输入长度小于验证输入长度小于 2if(_id.Length 2)_id=value;读取读取 ID 时调用时调用 将值将值赋给赋给 ID 时调用时调用 访问修饰符访问修饰符 数据类型数据类型 属性名属性名 get;set;读/写属性可以赋值和检索值可以赋值和检索值访问修饰符访问修饰符 数据类型数据类型 属性名属性名get;只读属性只能检索值只能检索值访问修饰符访问修饰符 数据类型数据类型 属性名属性名set;只写属性只能赋值只能赋值访问修饰符访问修饰符static 数据类型数据
4、类型 属性名属性名get;set;静态属性应用于整个类而不是类的实例应用于整个类而不是类的实例只能访问类的静态成员只能访问类的静态成员class SavingsAccount/类字段用于存储帐号、余额和已获利息类字段用于存储帐号、余额和已获利息private int _accountNumber;private double _balance;private double _interestEarned;/利率是静态的,因为所有帐户获得的利息相同利率是静态的,因为所有帐户获得的利息相同private static double _interestRate;/构造函数初始化类成员构造函数初始化类
5、成员public SavingsAccount(int accountNumber,double balance)this._accountNumber=accountNumber;this._balance =balance;/只读只读 AccountNumber 属性属性public int AccountNumbergetreturn _accountNumber;只读只读属性属性 static void Main(string args)/创建 SavingsAccount 的对象SavingsAccount objSavingsAccount=new SavingsAccount(1
6、2345,5000);Console.WriteLine(输入到现在为止已获得的利息和利率);objSavingsAccount.InterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console.WriteLine(获得的总利息为:0,objSavingsAcco
7、unt.InterestEarned);public double InterestEarnedgetreturn _interestEarned;set/验证数据验证数据if(value 0.0)Console.WriteLine(“利息利息 不能为负数不能为负数);return;_interestEarned=value;将设置 InterestEarned 属性static void Main(string args)/创建创建 SavingsAccount 的对象的对象SavingsAccount objSavingsAccount=new SavingsAccount(12345,5
8、000);Console.WriteLine(输入到现在为止已获得的利息和利率输入到现在为止已获得的利息和利率);objSavingsAccount.InterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console.WriteLine(获得的总利息为:获得的总利息
9、为:0,objSavingsAccount.InterestEarned);将设置 InterestRate 属性public static double InterestRategetreturn _interestRate;set/验证数据验证数据if(value 0.0)Console.WriteLine(“利率不能为负数利率不能为负数);return;else_interestRate=value/100;static void Main(string args)/创建创建 SavingsAccount 的对象的对象SavingsAccount objSavingsAccount=ne
10、w SavingsAccount(12345,5000);Console.WriteLine(“输入到现在为止已获得的利息和利率输入到现在为止已获得的利息和利率);objSavingsAccount.InterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console
11、.WriteLine(获得的总利息为:获得的总利息为:0,objSavingsAccount.InterestEarned);将检索将检索 Balance 和和 InterestRate 属性属性public double Balancegetif(_balance 0)Console.WriteLine(没有可用余额没有可用余额);return _balance;属性属性(Attribute)属性属性(Attribute)(Attribute)是一种新型的声明信息。是一种新型的声明信息。我们可以使用属性来定义设计时的信息我们可以使用属性来定义设计时的信息(比如比如帮助文件、文档的链接帮助文件
12、、文档的链接),以及运行时的信息,以及运行时的信息(比如将一个类的域与一个比如将一个类的域与一个XMLXML的域相关联的域相关联)。我们也可以用属性来创建我们也可以用属性来创建“自描述自描述”的组件的组件(可以提供该组件的描述信息可以提供该组件的描述信息)。预定义属性预定义属性 ConditionalConditional WebMethodWebMethod DllImportDllImport ObsoleteObsolete自定义属性自定义属性属性属性(Attribute)using System;using System;public class AnyClass public cla
13、ss AnyClass Obsolete(Obsolete(别用别用OldOld这个老方法了,请用这个老方法了,请用NewNew方法方法,true),true)static void Old()static void Old()static void New()static void New()public static void Main()public static void Main()Old();Old();.NET.NET框架允许创建自定义属性,它可以被框架允许创建自定义属性,它可以被用于存储信息和在运行时被获取。用于存储信息和在运行时被获取。这个信息可以与任何目标元素相关,依赖这个
14、信息可以与任何目标元素相关,依赖与设计和程序的需要。与设计和程序的需要。为了创建自定义属性,你需要:为了创建自定义属性,你需要:定义自定义属性定义自定义属性 命名自定义属性命名自定义属性 构造自定义属性构造自定义属性 为目标元素应用自定义属性为目标元素应用自定义属性创建自定义属性创建自定义属性定义自定义属性:定义自定义属性:一个新自定义属性类来源于一个新自定义属性类来源于System.AttributeSystem.Attribute系统类。系统类。你需要使用预定义的属性应用属性目标到新你需要使用预定义的属性应用属性目标到新的自定义属性类,的自定义属性类,AttributeUsage,Attr
15、ibuteUsage,如下面的如下面的代码所示:代码所示:AttributeUsage(AttributeTargets.Class|AttributeUsage(AttributeTargets.Class|AttributeTargets.Constructor|AttributeTargets.Constructor|AttributeTargets.Field|AttributeTargets.Field|AttributeTargets.Method|AttributeTargets.Method|AttributeTargets.Property,AttributeTargets.
16、Property,AllowMultiple=true)AllowMultiple=true)创建自定义属性(续)创建自定义属性(续)u AttributeUsageAttributeUsage属性接受两个参数:属性接受两个参数:一个参数是表示目标元素的一系列一个参数是表示目标元素的一系列标志。标志。其他参数是表示一个给定的元素是其他参数是表示一个给定的元素是否被应用于多个这样属性的标志。否被应用于多个这样属性的标志。u 除了除了AllowMultipleAllowMultiple特性,还有其他特性特性,还有其他特性可以与属性一起使用。这些特性是:可以与属性一起使用。这些特性是:Inherit
17、edInherited ValidOnValidOn创建自定义属性(续)创建自定义属性(续)下表列出了下表列出了AttributeTargetsAttributeTargets枚举器的各种成员名称。枚举器的各种成员名称。创建自定义属性(续)创建自定义属性(续)成员名称成员名称属性目标属性目标All元素包括汇编、类、类成员、代理、枚举、事件、域、接口、方法、模块、元素包括汇编、类、类成员、代理、枚举、事件、域、接口、方法、模块、参数、特性或结构参数、特性或结构Assembly仅汇编仅汇编Class类的实例类的实例ClassMembers类、结构、枚举、构造函数、方法、属性、域、事件、代理和接口类
18、、结构、枚举、构造函数、方法、属性、域、事件、代理和接口Constructor类构造函数类构造函数DelegateDelegate方法方法Enum定义的枚举定义的枚举Event定义的事件定义的事件Field域域Interface接口接口Method定义的方法定义的方法Module单一模块单一模块Parameter方法的参数方法的参数Property特性特性(get 和和 set,如果实现的话如果实现的话)Struct结构结构 命名自定义属性:命名自定义属性:通常的约定是在属性名称后添加单词通常的约定是在属性名称后添加单词AttributeAttribute。编译器通过允许你使用名称的简短版本来
19、调用编译器通过允许你使用名称的简短版本来调用属性以支持添加。属性以支持添加。创建自定义属性(续)创建自定义属性(续)构造自定义属性:构造自定义属性:每个属性必须包含至少一个构造函数。每个属性必须包含至少一个构造函数。位置参数通过构造函数被以构造函数中声明的位置参数通过构造函数被以构造函数中声明的顺序传递,如下面的代码段所示:顺序传递,如下面的代码段所示:public BugFixingAttribute(int BugNo,string public BugFixingAttribute(int BugNo,string Developer,string DateFixed)Developer
20、,string DateFixed)this.BugNo=BugNo;this.BugNo=BugNo;this.Developer=Developer;this.Developer=Developer;this.DateFixed=DateFixed;this.DateFixed=DateFixed;创建自定义属性(续)创建自定义属性(续)定位参数定位参数创建自定义属性(续)创建自定义属性(续)命名参数被实现为特性,如下面的代码命名参数被实现为特性,如下面的代码段所示:段所示:public string Remarkspublic string Remarks getget return R
21、emarks;return Remarks;set set Remarks=value;Remarks=value;为位置参数创建只读属性是很常见的:为位置参数创建只读属性是很常见的:public int BugNopublic int BugNo getget return BugNo;return BugNo;创建自定义属性(续)创建自定义属性(续)创建自定义属性(续)创建自定义属性(续)应用自定义属性:应用自定义属性:属性可以通过将它立刻放置在它的目标之前被应用。属性可以通过将它立刻放置在它的目标之前被应用。为了测试上述例子的为了测试上述例子的BugFixAttributeBugFixA
22、ttribute属性,你可属性,你可以创建一个简单的名为以创建一个简单的名为CalculatorCalculator类的程序,给出类的程序,给出四个函数。四个函数。你需要指定你需要指定BugFixAttributeBugFixAttribute为目标元素类以记录为目标元素类以记录它的代码维护历史,如下面的代码所示:它的代码维护历史,如下面的代码所示:BugFixingAttribute(125,Sara BugFixingAttribute(125,Sara Levo,08/15/06,Remarks=Return object Levo,08/15/06,Remarks=Return obj
23、ect not specified)not specified)BugFixingAttribute(159,Sara BugFixingAttribute(159,Sara Levo,08/17/06,Remarks=Data Type Levo,08/17/06,Remarks=Data Type Mismatch)Mismatch)AttributeUsage(AttributeTargets.All,AllowMultiple=false,Inherited=false)public class HelpAttribute:Attribute public HelpAttribute(
24、String Description_in)this.description=Description_in;protected String description;public String Description get return this.description;Help(this is a do-nothing class)public class AnyClass Help(this is a do-nothing method)/error public void AnyMethod()使用反射抽取元数据使用反射抽取元数据 反射在运行时被使用在获得类型信息的过程中。反射在运行时
25、被使用在获得类型信息的过程中。提供访问运行程序的元数据的类时在提供访问运行程序的元数据的类时在System.ReflectionSystem.Reflection命名空间中。命名空间中。System.ReflectionSystem.Reflection命名空间包含允许程序员命名空间包含允许程序员获取关于运行的程序的信息的类,以动态的添获取关于运行的程序的信息的类,以动态的添加类型、值和对象到那个程序。加类型、值和对象到那个程序。使用反射抽取元数据(续)使用反射抽取元数据(续)反射通常用于下面的任务:反射通常用于下面的任务:浏览元数据浏览元数据 完成类型发现完成类型发现 方法和特性的后期绑定方
26、法和特性的后期绑定 反射发出反射发出 使用反射抽取元数据(续)使用反射抽取元数据(续)浏览元数据:浏览元数据:为了使用反射来浏览元数据,为了使用反射来浏览元数据,System.ReflectionSystem.Reflection命名空间的命名空间的MemberInfoMemberInfo对象对象需要被实例化。需要被实例化。这个对象有助于发现成员的属性并且提供对元这个对象有助于发现成员的属性并且提供对元数据的访问。数据的访问。在本章中,你已经学到:在本章中,你已经学到:自定义属性是你根据需要创建的属性。自定义属性是你根据需要创建的属性。你添加属性的元素被称为属性目标。你添加属性的元素被称为属性目标。反射在运行时获取类型信息的过程中被使用。反射在运行时获取类型信息的过程中被使用。反射通常用于完成如下任务:反射通常用于完成如下任务:浏览元数据浏览元数据完成类型发现完成类型发现方法和属性的后期绑定方法和属性的后期绑定反射发出反射发出小结小结