在本章,你将学到: 应用属性 使用预定义属性 创建自定义属性...
DESCRIPTION
在本章,你将学到: 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据. 目标. 重点 应用属性 使用预定义属性 创建自定义属性 使用反射抽取元数据 难点 创建自定义属性 使用反射抽取元数据. 重点与难点. 教学计划. 对象是由它们的属性描述的。 属性是用于传递关于程序元素行为,例如类、枚举器和汇编的信息到运行时的声明标签。 声明标签是由放置在元素例如类或方法之前的方括号 ([ ]) 描述的。 属性被用来添加元数据例如编译器指令和其他信息,例如注释、描述、方法和程序的类。 .NET 框架具有许多预定义的属性。. 介绍属性. - PowerPoint PPT PresentationTRANSCRIPT
幻灯片 1(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
在本章,你将学到:应用属性使用预定义属性创建自定义属性
使用反射抽取元数据
目标
幻灯片 2(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
重点应用属性使用预定义属性创建自定义属性使用反射抽取元数据
难点创建自定义属性使用反射抽取元数据
重点与难点
幻灯片 3(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
序号 主题 计划教学时间(分钟 )
1 应用属性 15
2 使用预定义属性 15
3 创建自定义属性 90
4 使用反射抽取元数据 60
教学计划
幻灯片 4(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
对象是由它们的属性描述的。属性是用于传递关于程序元素行为,例如类、枚举器和汇编的信息到运行时的声明标签。声明标签是由放置在元素例如类或方法之前的方括号 ([ ]) 描述的。属性被用来添加元数据例如编译器指令和其他信息,例如注释、描述、方法和程序的类。.NET 框架具有许多预定义的属性。
介绍属性
幻灯片 5(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
属性被应用到不同的代码元素。属性被应用到不同的代码元素。这些元素包括汇编、模块、类、结构、枚举、构造函数、方法、特性、域、事件、接口、参数、返回值和代理。关于属性的信息被存储在与它们相关的元素的元数据中。下面的语法使你能够指定属性:[attribute(positional_parameters,name_parameter
= value, ...)] element
.NET 框架支持两种类型的属性以用于 C# 程序: 预定义自定义
应用属性
幻灯片 6(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
一些常用的 .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
使用预定义属性
幻灯片 7(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
一些常用的 .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; }}
使用预定义属性
幻灯片 8(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
运行结果如下
使用预定义属性
幻灯片 9(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
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);
}
}
使用预定义属性
幻灯片 10(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
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”}}
使用预定义属性
幻灯片 11(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
.NET 框架允许创建自定义属性,它可以被用于存储信息和在运行时被获取。这个信息可以与任何目标元素相关,依赖与设计和程序的需要。为了创建自定义属性,你需要:
1. 定义自定义属性2. 命名自定义属性3. 构造自定义属性4. 为目标元素应用自定义属性
创建自定义属性
幻灯片 12(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
定义自定义属性:一个新自定义属性类来源于 System.Attribute 系统类。你需要使用预定义的属性应用属性目标到新的自定义属性类, AttributeUsage, 如下面的代码所示:[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
创建自定义属性(续)
幻灯片 13(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
AttributeUsage 属性接受两个参数:一个参数是表示目标元素的一系列标志,表示下面的属性可以被应用在哪些数据元素中,如 method,class 等。是一个对属性使用范围作限制的参数其他参数是表示一个给定的元素是否被应用于多个这样属性的标志。
除了 AllowMultiple 特性,还有其他特性可以与属性一起使用。这些特性是:
Inherited :为 true 是表示该类使用的属性能被子类继承,为 false表不能被继承ValidOn :这个特性有助于定义目标元素,在它上面自定义属性被应用。
创建自定义属性(续)
幻灯片 14(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
下表列出了 AttributeTargets 枚举器的各种成员名称。
创建自定义属性(续)
成员名称 属性目标
All 元素包括汇编、类、类成员、代理、枚举、事件、域、接口、方法、模块、参数、特性或结构
Assembly 仅汇编
Class 类的实例
ClassMembers 类、结构、枚举、构造函数、方法、属性、域、事件、代理和接口
Constructor 类构造函数
Delegate Delegate 方法
Enum 定义的枚举
Event 定义的事件
Field 域
Interface 接口
Method 定义的方法
Module 单一模块
Parameter 方法的参数
Property 特性 (get 和 set, 如果实现的话 )
Struct 结构
幻灯片 15(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
命名自定义属性:通常的约定是在属性名称后添加单词 Attribute 。编译器通过允许你使用名称的简短版本来调用属性以支持添加。
创建自定义属性(续)
幻灯片 16(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
构造自定义属性:每个属性必须包含至少一个构造函数。位置参数通过构造函数被以构造函数中声明的顺序传递,如下面的代码段所示:
public BugFixingAttribute(int BugNo, string Developer,
string DateFixed)
{
this.BugNo = BugNo;
this.Developer = Developer;
this.DateFixed = DateFixed;
}
创建自定义属性(续)
幻灯片 17(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射创建自定义属性(续)
命名参数被实现为特性,如下面的代码段所示:public string Remarks
{
get
{
return Remarks;
}
set
{
Remarks = value;
}
}
幻灯片 18(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
为位置参数创建只读属性是很常见的:public int BugNo
{
get
{
return BugNo;
}
}
创建自定义属性(续)
幻灯片 19(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射创建自定义属性(续)
应用自定义属性:属性可以通过将它立刻放置在它的目标之前被应用。为了测试上述例子的 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
幻灯片 20(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射练习
创建一个属性,在一个类中应用,并把相关应用的属性元数据信息显示出来代码如下:
• 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();• }• }• }
幻灯片 21(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用反射抽取元数据
反射在运行时被使用在获得类型信息的过程中。提供访问运行程序的元数据的类时在 System.Reflection命名空间中。System.Reflection 命名空间包含允许程序员获取关于运行的程序的信息的类,以动态的添加类型、值和对象到那个程序。
幻灯片 22(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用反射抽取元数据(续)
反射通常用于下面的任务:浏览元数据 完成类型发现
方法和特性的后期绑定 反射发出
幻灯片 23(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用反射抽取元数据(续)
浏览元数据:为了使用反射来浏览元数据, System.Reflection 命名空间的 MemberInfo 对象需要被实例化。 这个对象有助于发现成员的属性并且提供对元数据的访问。
幻灯片 24(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用反射抽取元数据(续)
完成类型发现:反射也有助于浏览和检查汇编的内容。 它有助于发现与模块相关的类型;方法、域、属性和与类型相关的事件以及方法的每个类型的签名;类型支持的接口和类型的基类。类型发现信息也可以通过 Visual Studio .NET IDE 的对象浏览器窗口来浏览。
幻灯片 25(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用反射抽取元数据(续)
后期绑定:在运行时绑定一个方法被称为后期绑定。反射提供了选择一个你在运行时绑定的对象的灵活性,并且可以程序化的调用它。
幻灯片 26(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射使用带事件的反射
反射发出:反射发出允许在运行时创建新的类型,而且使用这些类型来完成某些任务。反射发出允许在运行时创建新的类型,而且使用这些类型来完成某些任务。
幻灯片 27(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射演示:创建和查询自定义属性信息
问题描述:John 是一个软件开发公司的开发人员。程序经理想让 John确保 Calculator 程序的商业逻辑的适当文档作为开发过程的一部分。尽管,公司维护一个独立的描述类的使用和它们的版本号的独立表格,当时程序经理想将表格添加到类中。
[ 提示:使用上面给出的 Calculator 类提供商业逻辑。 ]
幻灯片 28(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
解决方案:为了为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();
}
}
}
演示:创建和查询自定义属性信息(续)
幻灯片 29(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
1 、将自定义 Bugs修复属性和类描述属性合并到一个单一的程序中,使用反射从中获取相关描述数据。
主要目的 : 掌握属性的定义与使用
掌握使用反射抽取元数据的操作 计划完成时间:
45分钟
学生独立实践
幻灯片 30(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
在本章中,你已经学到:属性是用来传递关于程序元素,例如类、枚举器和汇编的行为信息到运行时的描述标签。.NET 框架支持两种用于 C# 程序的属性:预定义和自定义。预定义属性作为 CLR 的部分被支持,它们被集成到 .NET 。自定义属性是你根据需要创建的属性。你添加属性的元素被称为属性目标。反射在运行时获取类型信息的过程中被使用。反射通常用于完成如下任务:
浏览元数据完成类型发现方法和属性的后期绑定反射发出
小结
幻灯片 31(共 19张)
第 19 章Ver. 1.0
第 13 章 属性和反射
1 、编写一程序,利用自定义属性类来对另一个类的代码进行解释说明,并使用反射从中获取解释数据。
作业