310 likes | 426 Views
在本章,你将学到: 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据. 目标. 重点 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据 难点 创建自定义属性 使用反射抽取元数据. 重点与难点. 教学计划. 对象是由它们的属性描述的。 属性是用于传递关于程序元素行为,例如类、枚举器和汇编的信息到运行时的声明标签。 声明标签是由放置在元素例如类或方法之前的方括号 ([ ]) 描述的。 属性被用来添加元数据例如编译器指令和其他信息,例如注释、描述、方法和程序的类。 .NET 框架具有许多预定义的属性。. 介绍属性.
E N D
在本章,你将学到: 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据 目标
重点 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据 难点 创建自定义属性 使用反射抽取元数据 重点与难点
对象是由它们的属性描述的。 属性是用于传递关于程序元素行为,例如类、枚举器和汇编的信息到运行时的声明标签。 声明标签是由放置在元素例如类或方法之前的方括号([ ])描述的。 属性被用来添加元数据例如编译器指令和其他信息,例如注释、描述、方法和程序的类。 .NET框架具有许多预定义的属性。 介绍属性
属性被应用到不同的代码元素。 属性被应用到不同的代码元素。这些元素包括汇编、模块、类、结构、枚举、构造函数、方法、特性、域、事件、接口、参数、返回值和代理。关于属性的信息被存储在与它们相关的元素的元数据中。 下面的语法使你能够指定属性: [attribute(positional_parameters,name_parameter = value, ...)] element .NET框架支持两种类型的属性以用于C#程序: 预定义 自定义 应用属性
一些常用的.NET框架提供的预定义属性有: Conditional(条件)属性 引起方法调用的条件编译,依赖与特定的值例如Debug或Trace。这个属性决定当一个方法被调用的时候,将发生的动作(在代码执行过程中运不运行调用的函数的代码)示例如下: using System ; class HappyAppy { [conditional ( "DEBUG" )] public static void DebugOnlyMethod ( ) { Console.WriteLine ( "DEBUG is active!!" ) ; } public static void Main ( ){ DebugOnlyMethod ( ) ; } } #define DEBUG //只有在前面定义了,后面的DebugOnlyMethod 函数才会被调用 Class usefunction{ public static void Main ( ){ HappyAppy 0bj = new HappyAppy(); Obj.DebugOnlyMethod ( ) ; //因前面定义了,所以才会调用此函数 } } #if (DEBUG) Console.WriteLine(“DEBUG”); //在调试状态下运行此行代码 #else Console.WriteLine(“Release”); //在运行状态下运行些行代码 #endif 使用预定义属性
一些常用的.NET框架提供的预定义属性有: WebMethod 决定在网页服务中暴露的方法,示例如下: <@% WebService class="MathServiceJit" language="C#"%> using System.Web.Services;public class MathService{ [WebMethod] public double Add(double x, double y) { return x + y; } [WebMethod] public double Subtract(double x, double y) { return x - y; } public double Multiply(double x, double y) { return x * y; } public double Divide(double x, double y) { return x / y; }} 使用预定义属性
运行结果如下 使用预定义属性
DLLImport属性 在程序中调用在.net环境外开发的未管理的代码,如编译为DLL文件的标准C程序,如使用 kernel32.dll文件中的Beep(int f,int d)函数: using System; class geneBeeps{ [ DLLImport (kernel32.dll)] public static extern bool Beep(int f, int d); static void Main(){ Beep(1000,1111); } } 使用预定义属性
Obsolete(过时的)属性 using System; public Class Myclass{ [Obsolete(“提示A不能被使用,要使用B”,true)]//true表将产生一个错误,为false产生一个警告 static void A(){ } Staitc void B(){ } Public static void Main(){ A();//将产生一个错误,提示“A不能被使用,要使用B” } } 使用预定义属性
.NET框架允许创建自定义属性,它可以被用于存储信息和在运行时被获取。.NET框架允许创建自定义属性,它可以被用于存储信息和在运行时被获取。 这个信息可以与任何目标元素相关,依赖与设计和程序的需要。 为了创建自定义属性,你需要: 定义自定义属性 命名自定义属性 构造自定义属性 为目标元素应用自定义属性 创建自定义属性
定义自定义属性: 一个新自定义属性类来源于System.Attribute系统类。 你需要使用预定义的属性应用属性目标到新的自定义属性类,AttributeUsage,如下面的代码所示: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] 创建自定义属性(续)
AttributeUsage属性接受两个参数: 一个参数是表示目标元素的一系列标志,表示下面的属性可以被应用在哪些数据元素中,如method,class等。是一个对属性使用范围作限制的参数 其他参数是表示一个给定的元素是否被应用于多个这样属性的标志。 除了AllowMultiple特性,还有其他特性可以与属性一起使用。这些特性是: Inherited:为true是表示该类使用的属性能被子类继承,为false表不能被继承 ValidOn:这个特性有助于定义目标元素,在它上面自定义属性被应用。 创建自定义属性(续)
创建自定义属性(续) • 下表列出了AttributeTargets枚举器的各种成员名称。
命名自定义属性: 通常的约定是在属性名称后添加单词Attribute。 编译器通过允许你使用名称的简短版本来调用属性以支持添加。 创建自定义属性(续)
创建自定义属性(续) • 构造自定义属性: • 每个属性必须包含至少一个构造函数。 • 位置参数通过构造函数被以构造函数中声明的顺序传递,如下面的代码段所示: public BugFixingAttribute(int BugNo, string Developer, string DateFixed) { this.BugNo = BugNo; this.Developer = Developer; this.DateFixed = DateFixed; }
创建自定义属性(续) • 命名参数被实现为特性,如下面的代码段所示: public string Remarks { get { return Remarks; } set { Remarks = value; } }
为位置参数创建只读属性是很常见的: public int BugNo { get { return BugNo; } } 创建自定义属性(续)
应用自定义属性: 属性可以通过将它立刻放置在它的目标之前被应用。 为了测试上述例子的BugFixAttribute属性,你可以创建一个简单的名为Calculator类的程序,给出四个函数。 你需要指定BugFixAttribute为目标元素类以记录它的代码维护历史,如下面的代码所示: [BugFixingAttribute(125,"Sara Levo","08/15/06", Remarks="Return object not specified")] [BugFixingAttribute(159,"Sara Levo","08/17/06", Remarks="Data Type Mismatch")] public class Calculator 创建自定义属性(续)
创建一个属性,在一个类中应用,并把相关应用的属性元数据信息显示出来创建一个属性,在一个类中应用,并把相关应用的属性元数据信息显示出来 代码如下: using System; using System.Reflection; namespace Lesson13_Ex { // create BugFixingAttribute custom attribute to be assigned to class members [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] [DescriptionAttribute("This class contains defination of Bug Fixing attribute", 2.0)] public class BugFixingAttribute : System.Attribute { private int bugNo; private string developer; private string dateFixed; public string remarks; // attribute constructor for positional parameters public BugFixingAttribute(int BugNo, string Developer, string DateFixed) { this.bugNo = BugNo; this.developer = Developer; this.dateFixed = DateFixed; } public int BugNo { get { return bugNo; } } public string DateFixed { get { return dateFixed; } } public string Developer { get { return developer; } } public string Remarks { get { return remarks; } set { remarks = value; } } } // create DescriptionAttribute custom attribute to be assigned to class members [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] [DescriptionAttribute("This class contains defination of Description attribute", 1.0)] public class DescriptionAttribute : System.Attribute { // attribute constructor for positional parameters public DescriptionAttribute(string Description, double Version) { this.description = Description; this.version = Version; } protected String description; public String Description { get { return this.description; } } protected Double version; public Double Version { get { return this.version; } set { this.version = value; } } } [BugFixingAttribute(125, "Sara Levo", "08/15/06", Remarks = "Return object not specified")] [BugFixingAttribute(159, "Sara Levo", "08/17/06", Remarks = "Data Type Mismatch")] [DescriptionAttribute("This class contains two methods", 1.0)] public class Calculator { public double Add(Double num1, Double num2) { return num1 + num2; } public double Subtract(Double num1, Double num2) { return num1 - num2; } [BugFixingAttribute(155, "Sara Levo", "08/16/06")] public double Multiply(Double num1, Double num2) { return num1 * num2; } [BugFixingAttribute(156, "Sara Levo", "08/16/06")] public double Divide(Double num1, Double num2) { return num1 / num2; } } [DescriptionAttribute("This class contains the Main method", 2.0)] public class EntryPoint { public static void Main() { Calculator MyObj = new Calculator(); Console.WriteLine("The sum of specified two nos are: {0}", MyObj.Add(15, 20.5)); Type type = typeof(Calculator); // iterating through the attributes of the Calculator class foreach (Object attributes in type.GetCustomAttributes(typeof(BugFixingAttribute), false)) { BugFixingAttribute MyBFAObj = (BugFixingAttribute)attributes; if (null != MyBFAObj) { Console.WriteLine("\nBug #: {0}", MyBFAObj.BugNo); Console.WriteLine("Developer: {0}", MyBFAObj.Developer); Console.WriteLine("Date Fixed: {0}", MyBFAObj.DateFixed); Console.WriteLine("Remarks: {0}", MyBFAObj.Remarks); } } // iterating through the attributes of all the methods of a Calculator class foreach (MethodInfo method in type.GetMethods()) { foreach (Attribute attributes in method.GetCustomAttributes(true)) { BugFixingAttribute MyBFAObjM = (BugFixingAttribute)attributes; if (null != MyBFAObjM) { Console.WriteLine("\nBug #: {0} for Method: {1}", MyBFAObjM.BugNo, method.Name); Console.WriteLine("Developer: {0}", MyBFAObjM.Developer); Console.WriteLine("Date Fixed: {0}", MyBFAObjM.DateFixed); Console.WriteLine("Remarks: {0}", MyBFAObjM.Remarks); } } } foreach (Object attributes in type.GetCustomAttributes(typeof(DescriptionAttribute), false)) { DescriptionAttribute MyDAObj = (DescriptionAttribute)attributes; if (null != MyDAObj) { Console.WriteLine("\nClass : Calculator - Description :{0} - Version {1}", MyDAObj.Description, MyDAObj.Version); } } type = null; type = typeof(EntryPoint); foreach (Object attributes in type.GetCustomAttributes(false)) { DescriptionAttribute MyDAObj = (DescriptionAttribute)attributes; Console.WriteLine("\nClass : EntryPoint - Description :{0} - Version {1}", MyDAObj.Description, MyDAObj.Version); } Console.ReadLine(); } } } 练习
反射在运行时被使用在获得类型信息的过程中。反射在运行时被使用在获得类型信息的过程中。 提供访问运行程序的元数据的类时在System.Reflection命名空间中。 System.Reflection命名空间包含允许程序员获取关于运行的程序的信息的类,以动态的添加类型、值和对象到那个程序。 使用反射抽取元数据
反射通常用于下面的任务: 浏览元数据 完成类型发现 方法和特性的后期绑定 反射发出 使用反射抽取元数据(续)
浏览元数据: 为了使用反射来浏览元数据,System.Reflection命名空间的MemberInfo对象需要被实例化。 这个对象有助于发现成员的属性并且提供对元数据的访问。 使用反射抽取元数据(续)
完成类型发现: 反射也有助于浏览和检查汇编的内容。 它有助于发现与模块相关的类型;方法、域、属性和与类型相关的事件以及方法的每个类型的签名;类型支持的接口和类型的基类。 类型发现信息也可以通过Visual Studio .NET IDE的对象浏览器窗口来浏览。 使用反射抽取元数据(续)
后期绑定: 在运行时绑定一个方法被称为后期绑定。 反射提供了选择一个你在运行时绑定的对象的灵活性,并且可以程序化的调用它。 使用反射抽取元数据(续)
反射发出: 反射发出允许在运行时创建新的类型,而且使用这些类型来完成某些任务。 反射发出允许在运行时创建新的类型,而且使用这些类型来完成某些任务。 使用带事件的反射
问题描述: John是一个软件开发公司的开发人员。程序经理想让John确保Calculator程序的商业逻辑的适当文档作为开发过程的一部分。尽管,公司维护一个独立的描述类的使用和它们的版本号的独立表格,当时程序经理想将表格添加到类中。 [提示:使用上面给出的Calculator类提供商业逻辑。] 演示:创建和查询自定义属性信息
解决方案: 为了为Calculator程序创建基于控制台的程序,John需要完成下面的任务: 创建基于控制台的程序。 创建和执行程序。 程序代码 using System; using System.Reflection; namespace Lesson13_Ex { // create BugFixingAttribute custom attribute to be assigned to class members [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] [DescriptionAttribute("This class contains defination of Bug Fixing attribute", 2.0)] public class BugFixingAttribute : System.Attribute { private int bugNo; private string developer; private string dateFixed; public string remarks; // attribute constructor for positional parameters public BugFixingAttribute(int BugNo, string Developer, string DateFixed) { this.bugNo = BugNo; this.developer = Developer; this.dateFixed = DateFixed; } public int BugNo { get { return bugNo; } } public string DateFixed { get { return dateFixed; } } public string Developer { get { return developer; } } public string Remarks { get { return remarks; } set { remarks = value; } } } // create DescriptionAttribute custom attribute to be assigned to class members [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] [DescriptionAttribute("This class contains defination of Description attribute", 1.0)] public class DescriptionAttribute : System.Attribute { // attribute constructor for positional parameters public DescriptionAttribute(string Description, double Version) { this.description = Description; this.version = Version; } protected String description; public String Description { get { return this.description; } } protected Double version; public Double Version { get { return this.version; } set { this.version = value; } } } [BugFixingAttribute(125, "Sara Levo", "08/15/06", Remarks = "Return object not specified")] [BugFixingAttribute(159, "Sara Levo", "08/17/06", Remarks = "Data Type Mismatch")] [DescriptionAttribute("This class contains two methods", 1.0)] public class Calculator { public double Add(Double num1, Double num2) { return num1 + num2; } public double Subtract(Double num1, Double num2) { return num1 - num2; } [BugFixingAttribute(155, "Sara Levo", "08/16/06")] public double Multiply(Double num1, Double num2) { return num1 * num2; } [BugFixingAttribute(156, "Sara Levo", "08/16/06")] public double Divide(Double num1, Double num2) { return num1 / num2; } } [DescriptionAttribute("This class contains the Main method", 2.0)] public class EntryPoint { public static void Main() { Calculator MyObj = new Calculator(); Console.WriteLine("The sum of specified two nos are: {0}", MyObj.Add(15, 20.5)); Type type = typeof(Calculator); // iterating through the attributes of the Calculator class foreach (Object attributes in type.GetCustomAttributes(typeof(BugFixingAttribute), false)) { BugFixingAttribute MyBFAObj = (BugFixingAttribute)attributes; if (null != MyBFAObj) { Console.WriteLine("\nBug #: {0}", MyBFAObj.BugNo); Console.WriteLine("Developer: {0}", MyBFAObj.Developer); Console.WriteLine("Date Fixed: {0}", MyBFAObj.DateFixed); Console.WriteLine("Remarks: {0}", MyBFAObj.Remarks); } } // iterating through the attributes of all the methods of a Calculator class foreach (MethodInfo method in type.GetMethods()) { foreach (Attribute attributes in method.GetCustomAttributes(true)) { BugFixingAttribute MyBFAObjM = (BugFixingAttribute)attributes; if (null != MyBFAObjM) { Console.WriteLine("\nBug #: {0} for Method: {1}", MyBFAObjM.BugNo, method.Name); Console.WriteLine("Developer: {0}", MyBFAObjM.Developer); Console.WriteLine("Date Fixed: {0}", MyBFAObjM.DateFixed); Console.WriteLine("Remarks: {0}", MyBFAObjM.Remarks); } } } foreach (Object attributes in type.GetCustomAttributes(typeof(DescriptionAttribute), false)) { DescriptionAttribute MyDAObj = (DescriptionAttribute)attributes; if (null != MyDAObj) { Console.WriteLine("\nClass : Calculator - Description :{0} - Version {1}", MyDAObj.Description, MyDAObj.Version); } } type = null; type = typeof(EntryPoint); foreach (Object attributes in type.GetCustomAttributes(false)) { DescriptionAttribute MyDAObj = (DescriptionAttribute)attributes; Console.WriteLine("\nClass : EntryPoint - Description :{0} - Version {1}", MyDAObj.Description, MyDAObj.Version); } Console.ReadLine(); } } } 演示:创建和查询自定义属性信息(续)
1、将自定义Bugs修复属性和类描述属性合并到一个单一的程序中,使用反射从中获取相关描述数据。1、将自定义Bugs修复属性和类描述属性合并到一个单一的程序中,使用反射从中获取相关描述数据。 主要目的: 掌握属性的定义与使用 掌握使用反射抽取元数据的操作 计划完成时间: 45分钟 学生独立实践
在本章中,你已经学到: 属性是用来传递关于程序元素,例如类、枚举器和汇编的行为信息到运行时的描述标签。 .NET框架支持两种用于C#程序的属性:预定义和自定义。 预定义属性作为CLR的部分被支持,它们被集成到.NET。 自定义属性是你根据需要创建的属性。 你添加属性的元素被称为属性目标。 反射在运行时获取类型信息的过程中被使用。 反射通常用于完成如下任务: 浏览元数据 完成类型发现 方法和属性的后期绑定 反射发出 小结
1、编写一程序,利用自定义属性类来对另一个类的代码进行解释说明,并使用反射从中获取解释数据。1、编写一程序,利用自定义属性类来对另一个类的代码进行解释说明,并使用反射从中获取解释数据。 作业