.Net Attribute特性

1、什么是Atrribute 
首先,我们肯定Attribute是一个类,下面是msdn文档对它的描述: 
公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。

在.NET中,Attribute被用来处理多种问题,比如序列化、程序的安全特征、防止即时编译器对程序代码进行优化从而代码容易调试等等。下面,我们先来看几个在.NET中标准的属性的使用,稍后我们再回过头来讨论Attribute这个类本身。(文中的代码使用C#编写,但同样适用所有基于.NET的所有语言)

3、Attribute类 
除了.NET提供的那些Attribute派生类之外,我们可以自定义我们自己的Attribute,所有自定义的Attribute必须从Attribute类派生。现在我们来看一下Attribute 类的细节:

protected Attribute(): 保护的构造器,只能被Attribute的派生类调用。

三个静态方法:

static Attribute GetCustomAttribute():这个方法有8种重载的版本,它被用来取出施加在类成员上指定类型的Attribute。

static Attribute[] GetCustomAttributes(): 这个方法有16种重载版本,用来取出施加在类成员上指定类型的Attribute数组。

static bool IsDefined():由八种重载版本,看是否指定类型的定制attribute被施加到类的成员上面。

实例方法:

bool IsDefaultAttribute(): 如果Attribute的值是默认的值,那么返回true。

bool Match():表明这个Attribute实例是否等于一个指定的对象。

公共属性: TypeId: 得到一个唯一的标识,这个标识被用来区分同一个Attribute的不同实例。

我们简单地介绍了Attribute类的方法和属性,还有一些是从object继承来的。这里就不列出来了。

下面介绍如何自定义一个Attribute: 自定义一个Attribute并不需要特别的知识,其实就和编写一个类差不多。自定义的Attribute必须直接或者间接地从Attribute这个类派生,如:

public MyCustomAttribute : Attribute { ... }

这里需要指出的是Attribute的命名规范,也就是你的Attribute的类名+"Attribute",当你的Attribute施加到一个程序的元素上的时候,编译器先查找你的Attribute的定义,如果没有找到,那么它就会查找“Attribute名称"+Attribute的定义。如果都没有找到,那么编译器就报错。

4、定义或控制特性的使用

对于一个自定义的Attribute,你可以通过AttributeUsage的Attribute来限定你的Attribute 所施加的元素的类型。代码形式如下: 
[AttriubteUsage(参数设置)] public 自定义Attribute : Attribute { ... }

作为参数的AttributeTarges的值允许通过“或”操作来进行多个值得组合,如果你没有指定参数,那么默认参数就是All 。 AttributeUsage除了继承Attribute 的方法和属性之外,还定义了以下三个属性:

AllowMultiple: 读取或者设置这个属性,表示是否可以对一个程序元素施加多个Attribute 。

Inherited:读取或者设置这个属性,表示是否施加的Attribute 可以被派生类继承或者重载。

ValidOn: 读取或者设置这个属性,指明Attribute 可以被施加的元素的类型。

下面让我们来做一些实际的东西。我们将会在Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。

隐藏行号 复制代码 ?这是一段程序代码。

  1. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    
  2. public class HelpAttribute : Attribute
    
  3. {
    
  4.     public HelpAttribute(String Description_in)
    
  5.     {
    
  6.         this.description = Description_in;
    
  7.     }
    
  8. 
    
  9.     protected String description;
    
  10. 
    
  11.     public String Description
    
  12.     {
    
  13.         get
    
  14.         {
    
  15.             return this.description;
    
  16.         }
    
  17.     }
    
  18. }
    

代码讨论

  • 属性 AttributeUsage 指定该属性可以应用于的语言元素。
  • 属性类是从 System.Attribute 派生的公共类,至少有一个公共构造函数。
  • 属性类有两种类型的参数:
    • “定位参数”,每次使用属性时都必须指定这些参数。定位参数被指定为属性类的构造函数参数。在上面的示例中,url 便是一个定位参数。
    • “命名参数”,可选。如果使用属性时指定了命名参数,则必须使用参数的名称。通过包含非静态字段或属性来定义命名参数。在上面的示例中,Topic 便是一个命名参数。

先让我们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("this is a do-nothing class")]
    
  2. public class AnyClass
    
  3. {
    
  4.     [Help("this is a do-nothing method")] //error
    
  5.     public void AnyMethod()
    
  6.     {
    
  7.     }
    
  8. }
    

编译器报告错误如下:

AnyClass.cs: Attribute ‘Help‘ is not valid on this declaration type.

It is valid on ‘class‘ declarations only.

我们可以使用AttributeTargets.All来允许Help特性被放置在任何程序实体前。可能的值是:

Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface, 
Parameter,Delegate。

All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate,

ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface )

下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置多次。

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("this is a do-nothing class")]
    
  2. [Help("it contains a do-nothing method")]
    
  3. public class AnyClass
    
  4. {
    
  5.     [Help("this is a do-nothing method")] //error
    
  6.     public void AnyMethod()
    
  7.     {
    
  8.     }
    
  9. }
    

它产生了一个编译期错误。

AnyClass.cs: Duplicate ‘Help‘ attribute

Ok,现在我们来讨论一下最后的这个属性。Inherited, 表明当特性被放置在一个基类上时,它能否被派生类所继承。

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("BaseClass")]
    
  2. public class Base
    
  3. {
    
  4. }
    
  5. 
    
  6. public class Derive : Base
    
  7. {
    
  8. }
    

这里会有四种可能的组合:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]

第一种情况:

如果我们查询(Query)(稍后我们会看到如何在运行期查询一个类的特性)Derive类,我们将会发现Help特性并不存在,因为inherited属性被设置为false。

第二种情况:

和第一种情况相同,因为inherited也被设置为false。

第三种情况:

为了解释第三种和第四种情况,我们先来给派生类添加点代码:

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("BaseClass")]
    
  2. public class Base
    
  3. {
    
  4. }
    
  5. 
    
  6. [Help("DeriveClass")]
    
  7. public class Derive : Base
    
  8. {
    
  9. }
    

现在我们来查询一下Help特性,我们只能得到派生类的属性,因为inherited被设置为true,但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。

第四种情况:

在这里,我们将会发现派生类既有基类的Help特性,也有自己的Help特性,因为AllowMultiple被设置为true。

          • 通过反射访问属性

属性与程序元素关联后,可以使用反射查询属性存在及其值。查询属性的主要反射方法包含在 System.Reflection.MemberInfo 类(GetCustomAttributes 方法族)中。下面的示例演示使用反射获取对属性的访问的基本方法:

隐藏行号 复制代码 ?这是一段程序代码。

  1. System.Reflection.MemberInfo info = typeof(Help);
    
  2. object[] attributes = info.GetCustomAttributes(true);
    
  3. for (int i = 0; i < attributes.Length; i++)
    
  4. {
    
  5.     System.Console.WriteLine(attributes[i]);
    
  6. }
    

1.特性Attribute不能和属性Property混为一谈, 这是完全不同的两个东西.

2.特性Attribute给类或方法标识的内容, 可以在程序运行的时侯, 通过反射获取到.

例如1: .net添加的单元测试类, 里面有TestClass标识,里面的方法有TestMethod标识, 当用户想运行测试用例时, 一点按钮, 所有的测试用例类, 每个类中的测试方法就都显示在面前, 用户可以自由的选择运行哪些测试类及类中的哪些测试方法, 这是怎么做到的, 相信就是.net通过反射得到所有的TestClass标识的类, 做成一个list显示给用户, 点开这个类, 再通过反射得到所有该类中有TestMethod标识的方法, 再显示给用户, 就这样做到的.

例如2:[Obsolete("这是一个过时的方法")] 加在一个方法或类前时,编译器能提示您这是一个过时的方法,如何做到的?肯定是编译程序时要扫描方法前是否有这个标志,如果有,就给记录下来,显示出来。

3.特性Attribute这个东西类似静态的常量, 属于类所有, 不隶属于每一个特定的对象, 如果没有特性Attribute这个东西, 很多事情就很难做到.

4.内置的三个重要特性Attribute和一个枚举enum AttributeTargets

AttributeUsage
   ComVisible
   SerializableAttribute

后两个特性实际上代码很简单,就是一个标志, 如SerializableAttribute。

namespace System
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)]
    [ComVisible(true)]
    public sealed class SerializableAttribute : Attribute
    {
        public SerializableAttribute();
    }
}

AttributeUsage比较重要,有三个重要的参数可以设置,

AttributeTargets 这是一个枚举,列出了自定义特性可以用来修饰谁,Class, interface 或者全都可以,多个中间用|隔开。如果你用一个只允许AttributeTargets.Class的特性修饰一个interface去,那注定编译失败。

[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]

AllowMultiple 表示是否可以重复放置此特性来修饰一个方法或类。

[Lzd(Name = "Animal")]
    [Lzd(Name = "Animals")] 
    public class Animal
    {
        ...
    }

Inherited 表示是否可以被继承

如果Inherited = false,则派生类继承不了特性。

如果Inherited = true, 派生类可以继承特性,但是,如果AllowMultiple = false, 那么,如果派生类自己也加了同样的特性,则父类的特性会被屏蔽。

时间: 2024-11-05 13:51:02

.Net Attribute特性的相关文章

Attribute特性验证模型model

数据验证我们往往分为前台验证和后台验证,而我们的后台验证每到一个方法中就要去验证一次,这样的代码想想都难以维护,这篇我们这篇文章就是为了解决这样的问题.用attribute 这个特性来解决这样的问题 也将在这篇文章中告诉大家如何编写. 调用方式: UserService applictionService = container.Resolve<UserService>(); applictionService.AddUser(new User() { Name = "1"

mvc中利用Attribute特性来进行进行简单的登陆验证

前段时间一直比较忙.好不容易忙完.闲的没事干,就捣腾了下mvc(ef),因为以前都是用三层框架来进行开发,mvc用的也不是很多...众所周知,在三层里面我们一般都是建一个基类,然后在基类里面写验证登录方法,然后在需要验证登录的页面继承这个基类即可...但到了mvc里面所有的视图页面的操作都转移到了控制器了..这个时候我们在按照三层的方式建一个基类来继承验证登录,就没办法走通了...今天我就给大家来展示一个利用Attribute特性来验证登录.如果还有不知道这个东东的,可以百度一下Attribut

.net学习之Attribute特性和EF关键知识点

一.Attribute特性/标签1.Attribute用来对类.属性.方法等标注额外的信息,贴一个标签简单的说,定制特性Attribute,本质上就是一个类,它为目标元素提供关联附加信息,并在运行时以反射的方式来获取附加信息.[Obsolete("此方法已过时")]public void SayHi(){ }加上Obsolete特性,当鼠标放到调用方法上的时候,就会提示此方法已过时2.Attribute自定义特性类Attribute就是类,Attribute类名一般都以Attribut

.NET进阶篇03-Reflection反射、Attribute特性

知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 内容目录 一.概述二.反射1.反射使用2.创建对象3.调用方法4.字段属性三.特性四.总结 一.概述 反射其实无处不在,我们用VS进行调试时候,查看成员列表.修改变量值都是通过反射来实现的.我们写业务代码可能很少去写反射,但理解反射是从菜鸟到大牛的必经之路.无论EF还是ASP.NET,几乎所有框架都用到反射.反射动态创建对象.动态赋值.动态调用方法. 前面简单介绍过.NET的第一次编译,会编译成IL(中间语言),反射就是利用IL在运行时获取

IOC容器特性注入第五篇:查找(Attribute)特性注入

前面几篇文章分别介绍:程序集反射查找,特性,容器,但它们之间贯穿起来,形成查找Attribute注入IOC容器,就得需要下面这个类帮忙: 1.DependencyAttributeRegistrator(依赖特性注入类),有它才能在引擎初始化的时候 查找Attribute 进行注入 public class DependencyAttributeRegistrator { #region Fields private readonly ITypeFinder _finder; private r

C#基础系列——Attribute特性使用

前言:上篇 C#基础系列--反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术--特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属性.方法等具有某些统一的特征,从而达到某些特殊的需要.比如:方法的异常捕捉,你是否还在某些可能出现异常的地方(例如数据库的操作.文件的操作等)经常使用try...catch.这个时候如果使用特性,就可以大大减少方法里面的try...catch的使用.你只需要定义一个专门捕捉异常的特性类Excepti

关于C# 中的Attribute 特性

摘要:纠结地说,这应该算是一篇关于Attribute 的笔记,其中的一些思路和代码借鉴了他人的文笔(见本文底部链接).但是,由于此文对Attribute 的讲解实在是叫好(自夸一下 ^_^),所以公之于众,希望能对大家有所帮助. Attribute与Property 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各

(转)关于C# 中的Attribute 特性

摘要:纠结地说,这应该算是一篇关于Attribute 的笔记,其中的一些思路和代码借鉴了他人的文笔(见本文底部链接).但是,由于此文对Attribute 的讲解实在是叫好(自夸一下 ^_^),所以公之于众,希望能对大家有所帮助. Attribute与Property 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各

Attribute(特性)

一.特性是什么?特性有什么用? 特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签. 您可以通过使用特性向程序添加声明性信息.一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的. 使用特性,可以有效地将元数据或声明性信息与代码(程序集.类型.方法.属性等)相关联. 将特性与程序实体相关联后,可以在运行时使用反射这项技术查询特性. 二.声明和使用特性 [Obsolete("请不要使用这个了,请使用什么来代替&qu