CLR学习笔记--Attribute

本文详细介绍了Attribute在.NET中的应用,包括元数据体现、使用定制Attribute、定义自己的attribute类、检测定制attribute的方法,强调了Attribute在代码中的重要性和使用规则。文中通过示例代码阐述了Attribute的构造、限制及其在运行时的动态查询和处理。
摘要由CSDN通过智能技术生成

一、       引言

利用定制的Attribute,我样可以声明性地为自己的代码添加注解,从而实现一些特殊的功能。定制的Attribute允许将定义的信息应用于几乎每一个元数据表记录项(AttributeTargets枚举了可应用的所有项)

当我们将一个定制的Attribute应用于某个元数据,例如应用于某个类时,则在编译后,会在该类的元数据中的CustomerAttribute“注册表”中添加定制的Attribute记录。

因此对于定制的Attribute的真正的用处,是需要两个保证的,其一是编译器将定制的Attribute信息写入元数据,这个保证是基础,其二,既然元数据表记录项的CustomerAttribute “注册表”注册了某些Attribute,则在运行时,我们可动态的获取某个记录项(类、方法、字段等)中应用的Attribute实例,并获取实例中的信息,从而动态的改变代码的执行方式。

.NET的各种技术(Windows窗体、Web窗体、XML Web服务等)它们都应用了定制的Attribute,目的是方便开发者在代码中表达他们的意图

 

二、       定义Attribute在元数据中的体现

这一节原本是可以略过的,但是我觉得我还是有必要单独在一节里面对我在上面讲到的“编译后,会在该类的元数据中的CustomerAttribute“注册表”中添加定制的Attribute记录“这一句作个解释,了解这个,我觉得对去理解Attriubte的使用,有些很重要的意义。

举个例子来说明,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Attribute_Demo
{
    //[AttributeUsage(AttributeTargets.Class)]
    public class CClassAttribute : Attribute
    {
    }
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

此时注意CClassAttribute类,此时它没有应用于任何Attribute,我们来看一下编译器对它生成的元数据(ILDASM反编译器打开生成的exe,CTRL+M打开MetaInfo)如下:


然后我们将取消注释的定制属性代码,生成后再次查看CClassAttribute的元数据,如下:


我们对比一下CClassAttribute类型应用了属性AttributeUsageAttribute前后生成的元数据,显然编译器在生成应用了定制属性的AttributeUsageAttribute的CClassAttrubte元数据时,会将定制属性记录到CClassAttriubte的CustomAttribute的“注册表”中。

 

因此,对于类型、方法、字段等,可以在运行时,从它们的CustomAttribute的“注册表“中,查询是否应用了某些定制属性,从而动态的改变代码的执行方式。

 

三、       使用定制Attribute

C#允许将attribute应用于对以下任何目标元素进行定义的源代码:程序集、模块、类型(类、结构、委托、枚举、接口)、字段、方法(含构造器)、方法参数、方法返回值、属性、事件和泛型参数)

应用一个attribute时,C#允许一个前缀指定attribute应于的目标元素,许多情况,我们可以省略前缀,编译器一样能判断一个attribute应用于的元素目标,但有些情况,必须要指定一个前缀,来指定编译器清楚我们的意图,例如,当一个属性应用于事件时,如果不指定一个前缀,则编译器默认该属性只应用于事件,然而我们原本的意思是要将该属性应用于字段(事件的本质是一个私有的委托字段和Add和Remove方法)

下面的代码中,详细的例出所有可以应用的前缀,以及不能省略前缀的情况:

[assembly: SomeAttr] //应用于程序集  前缀不能省略
[module: SomeAttr]   //应用于模块    前缀可以省略

[type: SomeAttr]     //应用于类型    前缀可以省略
internal class SomeType
{
    [field: SomeAttr] //应用于字段   前缀可以省略
    public Int32 SomeField = 0;

    [return: SomeAttr] //应用于返回值 前缀不能省略 如省略编译器默认应用于方法
    [method: SomeAttr]  //应用于方法   前缀可以省略 
    public Int32 SomeMethod([param: SomeAttr] //应用于参数  前缀可以省略
            Int32 para)
    {
        return para;
    }

    [property: SomeAttr] //应用于属性  前缀可以省略
    public Int32 SomeProp
    {
        [method: SomeAttr]//应用于get访问器方法,前缀可以省略
        get { return SomeField; }
    }

    [event: SomeAttr] //应用于事件  前缀可以省略
    [field: SomeAttr] //应用于编译器生成的委托字段 前缀不能省略 如省略编译器默认应用于事件
    [method: SomeAttr]//应用于编译器生成的add和remove方法,前缀不能省略,如省略编译器默认应用于事件
    public event EventHandler SomeEvent;

}

通过上面的示代码示例,我们知道,当attribute应用于某一项时,编译器会默认指定它应用的实际项,例如当一个attribute应用于字段时,此时可以将field前缀省略,因为这个属性只能作用于字段,但如果把一个作用于field的attribute应用于事件时,如果省略field前缀,则编译器默认作用于事件本身,这就与我们原本的意图不相符,因此在这种情况下,我们需要显示指定一个attribute前缀。

 

在介绍定制的Attribute之前,我们先来了解下attribute的使用规则

1、 定制attribute为必须直接或者间接地从公共抽象类System.Attribute派生

2、 attribute必须有一个公共构造器

3、 attribute可能支持一些特殊的语法,允许你设置与attribute类关联的公共字段或属性

4、 多个attribute可应用于单个目标元素

5、 可将每个attribute都封闭到一对方括号内,也可在一对方括号内以多个逗号分隔的attribute,如果attribute类构造器不获取参数,圆括号就是可有可无

6、 attribute类的后缀”Attribute”是可选的

 

四、       定义自己的attribute类

我们定义一个attribute类如下:

internal class TableAttribute : Attribute
{
    public TableAttribute()
    {
    }
}

此时我们定义了一个TableAttribute类,此时这个attribute没有什么实际意义

1、 它从Attribute派生

2、 它有一个公共的构造函数

3、 为了保持与标准的相容性,TableAttribute类有一个Attribute后缀,但这不是必须的,所以你完全可以定义类名为TableSomeSuffex或者其他一些名称

最重要的这个TableAttribute可以用于任何目标元素,因此问题出现了,有时候我们想定义一个attribute只用于类,或者字段,而不想它用于方法,这时就需要一个限制,例如.NET的内置的Attribute,FlagAttribute只能用于struct,而不能作用于类或者字段

 

这时我们有必要去了解一个只能作用于attribute的attribute类---AttributeUsageAttribute

这里有点呦口,意思是指:

它只能作用于Attribute派生的类,这里隐藏了两个信息

1、 它只能作用于类(class)

2、 它只能作用派生自Attribute的类

例如下面的用法,是错误的,编译器会抛出:特性AttributeUsageAttribute仅在从System

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值