当前位置:编程学习 > C#/ASP.NET >>

C#自定义特性介绍

本文通过实例介绍了C#自定义特性。如果不能自己定义一个特性并使用它,我想你怎么也不能很好的理解特性。
AD:

C#自定义特性范例介绍
如果不能自己定义一个特性并使用它,我想你怎么也不能很好的理解特性,我们现在就自己构建一个特性。假设我们有这样一个很常见的需求:我们在创建或者更新一个类文件时,需要说明这个类是什么时候、由谁创建的,在以后的更新中还要说明在什么时候由谁更新的,可以记录也可以不记录更新的内容,以往你会怎么做呢?是不是像这样在类的上面给类添加注释:
//更新:Matthew, 2008-2-10, 修改 ToString()方法 
//更新:Jimmy, 2008-1-18 
//创建:张子阳, 2008-1-15 
public class DemoClass{ 
    // Class Body 
}
这样的的确确是可以记录下来,但是如果有一天我们想将这些记录保存到数据库中作以备份呢?你是不是要一个一个地去查看源文件,找出这些注释,再一条条插入数据库中呢?
通过上面特性的定义,我们知道特性可以用于给类型添加元数据(描述数据的数据,包括数据是否被修改、何时创建、创建人,这些数据可以是一个类、方法、属性),这些元数据可以用于描述类型。那么在此处,特性应该会派上用场。那么在本例中,元数据应该是:注释类型(“更新”或者“创建”),修改人,日期,备注信息(可有可无)。而特性的目标类型是DemoClass类。
按照对于附加到DemoClass类上的元数据的理解,我们先创建一个封装了元数据的类RecordAttribute:
public class RecordAttribute {    
    private string recordType;      // 记录类型:更新/创建    
    private string author;          // 作者    
    private DateTime date;          // 更新/创建 日期    
    private string memo;         // 备注    
   
    // 构造函数,构造函数的参数在特性中也称为“位置参数”。    
    public RecordAttribute(string recordType, string author, string date) {    
       this.recordType = recordType;    
       this.author = author;    
       this.date = Convert.ToDateTime(date);    
    }    
   
    // 对于位置参数,通常只提供get访问器    
    public string RecordType {   get { return recordType; }   }    
    public string Author { get { return author; } }    
    public DateTime Date { get { return date; } }    
   
    // 构建一个属性,在特性中也叫“命名参数”    
    public string Memo {    
       get { return memo; }    
       set { memo = value; }    
    }    
}   
 
NOTE:注意构造函数的参数 date,必须为一个常量、Type类型、或者是常量数组,所以不能直接传递DateTime类型。
这个类不光看上去,实际上也和普通的类没有任何区别,显然不能它因为名字后面跟了个Attribute就摇身一变成了特性。那么怎样才能让它称为特性并应用到一个类上面呢?进行下一步之前,我们看看.Net内置的特性Obsolete是如何定义的:
namespace System { 
    [Serializable] 
    [AttributeUsage(6140, Inherited = false)] 
    [ComVisible(true)] 
    public sealed class ObsoleteAttribute : Attribute { 
 
       public ObsoleteAttribute(); 
       public ObsoleteAttribute(string message); 
       public ObsoleteAttribute(string message, bool error); 
 
       public bool IsError { get; } 
       public string Message { get; } 
    } 
}  
添加特性的格式(位置参数和命名参数)
首先,我们应该发现,它继承自Attribute类,这说明我们的 RecordAttribute 也应该继承自Attribute类。 (一个特性类与普通类的区别是:继承了Attribute类)
其次,我们发现在这个特性的定义上,又用了三个特性去描述它。这三个特性分别是:Serializable、AttributeUsage 和 ComVisible。Serializable特性我们前面已经讲述过,ComVisible简单来说是“控制程序集中个别托管类型、成员或所有类型对 COM 的可访问性”(微软给的定义)。这里我们应该注意到:特性本身就是用来描述数据的元数据,而这三个特性又用来描述特性,所以它们可以认为是“元数据的元数据”(元元数据:meta-metadata)。
(从这里我们可以看出,特性类本身也可以用除自身以外的其它特性来描述,所以这个特性类的特性是元元数据。)
因为我们需要使用“元元数据”去描述我们定义的特性 RecordAttribute,所以现在我们需要首先了解一下“元元数据”。这里应该记得“元元数据”也是一个特性,大多数情况下,我们只需要掌握 AttributeUsage就可以了,所以现在就研究一下它。我们首先看上面AttributeUsage是如何加载到ObsoleteAttribute特性上面的。
[AttributeUsage(6140, Inherited = false)]
然后我们看一下AttributeUsage的定义:
namespace System { 
    public sealed class AttributeUsageAttribute : Attribute { 
       public AttributeUsageAttribute(AttributeTargets validOn); 
 
       public bool AllowMultiple { get; set; } 
       public bool Inherited { get; set; } 
       public AttributeTargets ValidOn { get; } 
    } 

 
可以看到,它有一个构造函数,这个构造函数含有一个AttributeTargets类型的位置参数(Positional Parameter) validOn,还有两个命名参数(Named Parameter)。注意ValidOn属性不是一个命名参数,因为它不包含set访问器,(是位置参数)。
这里大家一定疑惑为什么会这样划分参数,这和特性的使用是相关的。假如AttributeUsageAttribute 是一个普通的类,我们一定是这样使用的:
// 实例化一个 AttributeUsageAttribute 类
AttributeUsageAttribute usage=new AttributeUsageAttribute(AttributeTargets.Class);
usage.AllowMultiple = true;  // 设置AllowMutiple属性
usage.Inherited = false;// 设置Inherited属性
但是,特性只写成一行代码,然后紧靠其所应用的类型(目标类型),那么怎么办呢?微软的软件工程师们就想到了这样的办法:不管是构造函数的参数 还是 属性,统统写到构造函数的圆括号中,对于构造函数的参数,必须按照构造函数参数的顺序和类型;对于属性,采用“属性=值”这样的格式,它们之间用逗号分隔。于是上面的代码就减缩成了这样:
[AttributeUsage(AttributeTargets.Class, AllowMutiple=true, Inherited=false)]
可以看出,AttributeTargets.Class是构造函数参数(位置参数),而AllowMutiple 和 Inherited实际上是属性(命名参数)。命名参数是可选的。将来我们的RecordAttribute的使用方式于此相同。(为什么管他们叫参数,我猜想是因为它们的使用方式看上去更像是方法的参数吧。)
假设现在我们的RecordAttribute已经OK了,则它的使用应该是这样的:
C#代码
[RecordAttribute("创建","张子阳","2008-1-15",Memo="这个类仅供演示")]    
public class DemoClass{    
    // ClassBody    
}    
其中recordType,

补充:软件开发 , C# ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,