本文来之:http://hi.baidu.com/sanlng/item/afa31eed0a383e0e570f1d3e

在一般的应用中,特性(Attribute,以称为属性)好像被使用的不是很多。其实特性是一个很有用的东西,也是.net的一个重要组成部分。

1、特性是什么?

特性是一种向类添加代码的方法,这些代码以声明的形式来修饰程序集、类以及其它代码元素。这种修饰类似于public、private等关键字对一个方法的修饰,与之不同的是,多数特性并不与特定的语言相关,所以在使用特性时可以在不需要改变编译器的情况下扩展语言功能。

2、特性有什么用

特性是.net中一个重要的组成部分,.net在很多地方都使用了特性,见下面的文字。

  • 在 XML Web services 中,使用 WebMethod 特性标记方法,以指示该方法应可通过 SOAP 协议进行调用。有关更多信息,请参见 WebMethodAttribute 类
  • 描述当与本机代码进行交互操作时如何封送方法参数。有关更多信息,请参见 MarshalAsAttribute 类
  • 描述类、方法和接口的 COM 属性。
  • 将组件标记为 COM,以便 Visual Basic 编译器生成创建 COM 组件所需的附加代码。有关更多信息,请参见 ComClassAttribute 类
  • 使用 DllImportAttribute 类调用非托管代码。
  • 在标题、版本、说明或商标方面描述您的程序集。
  • 描述要持久性序列化类的哪些成员。
  • 描述如何映射类成员和 XML 节点以便进行 XML 序列化。
  • 描述方法的安全要求。
  • 指定用于强制安全性的特性。
  • 由实时 (JIT) 编译器控制优化,以便易于调试代码。

    以上文字来自MSDN。网址:

    http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vbcn7/html/vaconcommonusesforattributes.asp

  • 3、C#中的特性类

    C#中的所有特性的基类都是Attribute的子类。特性在使用的时候不同于一般的类。特性在使用的时候需要将其与某种代码元素(如一个类或一个方法)关联起来,并且只有在特性被搜索到时才能实例化和使用。还有有趣的一点是,特性的添加并不会为你的程序添加任何可执行代码,程序在编译时只是将其添加程序集里,所以如果你想使用元数据中的某个特性,那你就得先去搜索。

    4、如何使用特性

    ●使用系统特性类

  • Obsolete特性

    该特性用于标识不再使用的代码元素,见下面的代码(代码片断1)

              [Obsolete("该方法将在下一版中被删除")]
    public string ReturnValue(string OutValue)
    {
    return OutValue ;
    }

    (代码片断1)

    ReturnValue()方法被Obsolete进行标记,这样当包含这个方法的类被实例化且该方法被调用时,编译器将给出警告信息,但程序依旧可以执行。

    因为特性是一个类,所以其拥有构造函数,并且还可能具有被重载了的带参数的构造函数,下面的代码使用了带有两个参数的特性构造函数

              [Obsolete("该方法将在下一版中被删除",false)]
    public string ReturnValue(string OutValue)
    {
    return OutValue ;
    }

    (代码片断2)

    Obsolete的这个构造函数中的第二个参数用于表示在编译器编译时是否将过时代码视为错误,我们这里将其指定为false,即不视为错误处理。如果将其指定为true,则对过时方法的调用将引发异常,程序不能被编译。如下代码

              [Obsolete("该方法将在下一版中被删除",true)]
    public string ReturnValue(string OutValue)
    {
    return OutValue ;
    }

    (代码片断3)

    前面讲到过,特性只有被专门的特性搜索工具搜索到之后才能实例化和使用,Obsolete特性由编译器搜索检查并搜索,其它一些特性则由.net架框中的类进行检查和搜索。

    .net中还有大量的特性可供使用,如控制对象序列化、标识Web Service之类的特性。按照惯例,.net中,所有的特性其类名都是以Attribute结尾的,包括编译器在搜索一个特性时如果没有找到,会自动在该特性名之后加上Attribute继续搜索。

    ●自定义特性类

    下面我们将自己定义一个特性。定义一个特性与定义一个类没有什么区别,我们只需要指定其从Attribute基继承即可。下面的代码定义了一个特性,该特性用于指定一个代码元素的作者、电话以及该元素的注释内容

     namespace MyClass
    {
    /// <summary>
    /// 标记一个类的作者、注释与电话
    /// </summary>
    public class AuthorAttribute : Attribute
    {
    private string _Name; private string _Note; private string _Tel; public AuthorAttribute()
    {
    //
    // TODO: 在此处添加构造函数逻辑
    //
    } public AuthorAttribute(string Name)
    {
    _Name = Name;
    } /// <summary>
    /// 用于获取或设置代码元素的作者
    /// </summary>
    public string Name
    {
    get
    {
    return _Name;
    }
    set
    {
    _Name = value;
    }
    } /// <summary>
    /// 用于获取或设置代码元素的注释
    /// </summary>
    public string Note
    {
    get
    {
    return _Note;
    }
    set
    {
    _Note = value;
    }
    } /// <summary>
    /// 用于获取或设置代码元素作者的电话
    /// </summary>
    public string Tel
    {
    get
    {
    return _Tel;
    }
    set
    {
    _Tel = value;
    }
    } /// <summary>
    /// 用于获取对代码元素的注释
    /// </summary>
    /// <returns></returns>
    public string GetNote()
    {
    if (_Note == null)
    {
    return "没有添加任何注释!";
    }
    else
    {
    return _Note;
    }
    }
    }
    }
  • (代码片断4)

    下面的MemberInfo()方法使用了我们上面定义的特性

            [AuthorAttribute("henry")]
    public string MemberInfo(string OutValue)
    {
    return "该会员名称:" + _Name + ";该会员所属国家:" + _Country ;
    }

    (代码片断5)

    上面定义的特性类可以附加在任何代码元素之上,稍后我们将看到如何控制一个特性的具体应用,比如只允许一个特性附加在方法而不是属性上。

    5、搜索特性

    怎么样判断一个代码元素上是否使用了特性了呢?这里需要使用反射来搜索一个代码元素是否使用了特性。

    下面是自定义的一个测试类

     namespace MyClass
    {
    /// <summary>
    /// 会员类,封装了有关会员信息与操作
    /// </summary>
    public class Member
    { private string _Name = ""; private string _Country = "中国"; public string Name
    {
    get
    {
    return _Name;
    } set
    {
    _Name = value;
    }
    } public string Country
    {
    get
    {
    return _Country;
    } set
    {
    _Country = value;
    }
    } public Member()
    {
    //
    // TODO: 在此处添加构造函数逻辑
    //
    } public string MemberName()
    {
    if (_Name == "")
    {
    return "没有为该会员设置名称!";
    }
    else
    {
    return _Name;
    }
    } public string MemberCountry()
    {
    return _Country;
    } public string MemberInfo(string OutValue)
    {
    return "该会员名称:" + _Name + ";该会员所属国家:" + _Country;
    }
    }
    }

    (代码片断6)

    现在,我们假设在Member类开始定义的顶部即public class Member一行的上面使用了我们定义好的特性类AuthorAttribute[AuthorAttribute("henry")],那么我们可以利用以下代码来检查Member类的作者到底是谁。

       

                 Member TMember = new Member();
    Type T = TMember.GetType();
    foreach (Attribute attribute in T.GetCustomAttributes(true))
    {
    AuthorAttribute author = attribute as AuthorAttribute;
    if (author != null)
    {
    Response.Write(author.Name);
    }
    }

    (代码片断7)

    最后打印出的结果是“henry”,从而得出Member类应用了AuthorAttribute 类并指定其作者为henry。如果对反射不清楚,我的博客上有关于反射基本应用的文章,不妨参考一下。

    上面的代码(代码片断7)可以找出一个特定的类型是否使用了自定义特性。如果我们把AuthorAttribute 特性应用到了Member类的某个方法上而不是Member类上,那么上面的代码能够找到AuthorAttribute 特性吗?

    答案是不能的。如果AuthorAttribute 特性应用在了一个方法上,以上代码什么都找不到。以下代码在指定的方法上搜索AuthorAttribute 特性。这里我们假设AuthorAttribute 特性应用到子Member类的MemberInfo()公共方法上,即

          [Author("henry")]
    public string MemberInfo(string OutValue)
    {
    return "该会员名称:" + _Name + ";该会员所属国家:" + _Country ;
    }

    (代码片断8)

    注意[Author("henry")]一句,这里的Author("henry")等同于AuthorAttribute("henry")。

    以下代码将在MemberInfo()方法上进行搜索

                 Member TMember = new Member();
    Type T = TMember.GetType();
    MethodInfo TMethodInfo = T.GetMethod("MemberInfo");
    if (TMethodInfo != null)
    {
    foreach (Attribute attribute in TMethodInfo.GetCustomAttributes(true))
    {
    AuthorAttribute author = attribute as AuthorAttribute;
    if (author != null)
    {
    Response.Write(author.Name);
    }
    }
    }

    (代码片断9)

    上面的代码(代码片断9)你完全可以进行进一步的封装以便返回每个公共方法上的AuthorAttribute 的特性。我就不写了。

    到这里为止,你可能已经发现另外一个问题了,那就是如果我想指定一个特性只能应用于特定的代码元素上(比如公共方法)该怎么办?

    6、控制特性的应用范围

    使用AttributeUsage特性可以控件自定义特性的使用。该特性有三个参数:

    ValidOn:这是特性应用位置参数,定义了一个自定义特性能够应用到那种编程元素上,是方法还是属性

    AllowMultiple:命名参数,它指定一个特性能否在一个程序集中被多次使用

    Inherited:命名参数,用于控制一个自定义特性是否能被该类型的子类继承

    其中,位置参数ValidOn使用AttributeTargets枚举,该枚举的可取值可以参阅MSDN文档。现在我们使用这个位置参数控制我们上面定义的自定义特性只能用于方法之上。见下面的代码

     namespace MyClass
    {
    /// <summary>
    /// 标记一个类的作者、注释与电话
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class AuthorAttribute : Attribute
    {
    private string _Name; private string _Note; private string _Tel; public AuthorAttribute()
    {
    //
    // TODO: 在此处添加构造函数逻辑
    //
    } public AuthorAttribute(string Name)
    {
    _Name = Name;
    } /// <summary>
    /// 用于获取或设置代码元素的作者
    /// </summary>
    public string Name
    {
    get
    {
    return _Name;
    }
    set
    {
    _Name = value;
    }
    } /// <summary>
    /// 用于获取或设置代码元素的注释
    /// </summary>
    public string Note
    {
    get
    {
    return _Note;
    }
    set
    {
    _Note = value;
    }
    } /// <summary>
    /// 用于获取或设置代码元素作者的电话
    /// </summary>
    public string Tel
    {
    get
    {
    return _Tel;
    }
    set
    {
    _Tel = value;
    }
    } /// <summary>
    /// 用于获取对代码元素的注释
    /// </summary>
    /// <returns></returns>
    public string GetNote()
    {
    if (_Note == null)
    {
    return "没有添加任何注释!";
    }
    else
    {
    return _Note;
    }
    }
    }
    }

    (代码片断10)

    然后,我们(代码片断10)上面定义的特性应用到一个方法之上。

         [Author("henry")]
    public string MemberInfo(string OutValue)
    {
    return "该会员名称:" + _Name + ";该会员所属国家:" + _Country ;
    }

    (代码片断11)

    你可以尝试将该特性应用到一个属性会出现什么样的结果。

    [AttributeUsage(AttributeTargets.Method)]在使用的时候还可以用“|”将几个不同的AttributeTargets枚举隔开,如

    [AttributeUsage(AttributeTargets.Method|AttributeTargets.Property)]

    这样,这个特性就可以在属性与方法上同时使用了,如果将AttributeTargets设置为All,则允许这个特性在程序的任何元素上使用。

    在默认情况下,特性是不能被子类继承的,如果需要让一个特性可以被子类继承,则需要将AttributeUsage特性的Inherited设置为true,如下代码

    [AttributeUsage(AttributeTargets.All,Inherited=true)]

    这样,自定义特性将可以被任何程序元素使用,且允许子类继承。

    AllowMultiple允许一个特性可被多次的应用到一个代码元素上。但在默认情况下,这是不允许的。见下面的代码

    [AttributeUsage(AttributeTargets.ALL,AllowMultiple=true)]

    然后在Member类的MemberInfo()应用该特性

         [Author("Tom")]
    [Author("henry")]
    public string MemberInfo(string OutValue)
    {
    return "该会员名称:" + _Name + ";该会员所属国家:" + _Country ;
    }

    只能写到这里了,我也很少用这个东西,希望可以与高手一起交流。

.net中的特性的更多相关文章

  1. C#中的 特性 详解(转载)

    本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...

  2. java 对象的this使用 java方法中参数传递特性 方法的递归

    一.this关键字,使用的情形,以及如何使用. 1.使用的情形 类中的方法体中使用this  --初始化该对象 类的构造器中使用this --引用,调用该方法的对象 2.不写this,调用 只要方法或 ...

  3. Performance Tuning guide 翻译 || Performance Tuning Guide 11G中新增特性

    CSDN 对格式支持比較弱.能够到http://user.qzone.qq.com/88285879/blog/1399382878 看一致的内容. Performance Tuning Guide  ...

  4. C#中的特性 (Attribute) 入门 (二)

    C#中的特性 (Attribute) 入门 (二) 接下来我们要自己定义我们自己的特性,通过我们自己定义的特性来描述我们的代码. 自定义特性 所有的自定义特性都应该继承或者间接的继承自Attribut ...

  5. C#中的特性 (Attribute) 入门 (一)

    C#中的特性 (Attribute) 入门 (一) 饮水思源 http://www.cnblogs.com/Wind-Eagle/archive/2008/12/10/1351746.html htt ...

  6. Lithium中关键特性更新

    Lithium中关键特性更新 1. Lithium特性更新概述 Lithium相对于Helium更新特性共27项,其中原有特性提升或增强13项,新增特性14项,如下表所示 特性类型 相对于Helium ...

  7. c#中的特性

    c#中的特性 特性在我的理解就是在类或者方法或者参数上加上指定的标记,然后实现指定的效果. 和Java中的注解@Annotation类似. c#内置的特性之Obsolete [Obsolete(&qu ...

  8. PHP中面向对象特性实现

    PHP近些年来成为全球最流行的网页编程语言,该语言以弱类型.易兼容.门槛低.开发快.功能强著称,且听别人这么说,我在有了c和c#基础后学习PHP过程中也并不是很顺利,该语言的一些特殊的语法规则又是让我 ...

  9. PHP中Trait特性

    Trait是自 PHP 5.4.0 起添加的一个新特性,是 PHP 多重继承的一种解决方案.例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情,Trait 就是为了解决这个 ...

随机推荐

  1. DataGrid 简单数据绑定实例1

    1.默认数据显示(自动显示列) 后台绑定 //DataGrid 数据绑定 dataGridOne.ItemsSource = _Context.Info.ToList(); 前台定义 <Data ...

  2. shell获取文件行数

    获取文件行数: echo `cat $file | wc -l` 获取文件中不重复的行数(去重后) echo `awk '{$1="";print $0;}' $file_tel ...

  3. zepto源码研究 - deferred.js(jquery-deferred.js)

    简要:zepto的deferred.js 并不遵守promise/A+ 规范,而在jquery v3.0.0中的defer在一定程度上实现了promise/A+ ,因此本文主要研究jquery v3. ...

  4. 小巧实用的数字加减插件(jquery插件)

    2015-12-04 近期项目需要,我将插件更新了,增加了两个参数,一个参数控制文本框是否支持输入,另一个参数则是新增了一个回调函数,返回文本框内的值.另外对代码局部重构了,优化了一下封装,需要的朋友 ...

  5. 单片机串口通讯RXD与TXD如何对接详解

    相信很多人都对单片机与计算机或者芯片通信时,RXD与TXD如何连接比较困惑.因为在一些电路图中,有的是直连接法,有的是交叉接法,让人有点摸不着头脑. 首先需要明白两个概念,就是DTE和DCE.DTE是 ...

  6. windows设备驱动安装接口(自己仿写)

    /***************************************** Author:foo_hack This is File named:Setup.h The Funtion Im ...

  7. logstash 利用drop 丢弃过滤日志

    input { stdin { } } filter { grok { match => ["message","\s*%{TIMESTAMP_ISO8601}\s ...

  8. 【转】Service Intent must be explicit的解决方法

    原文网址:http://blog.csdn.net/shenzhonglaoxu/article/details/42675287 今天在学习android的Service组件的时候,在Android ...

  9. [转]Ubuntu Tweak 0.8.7 发布:支持 Ubuntu 14.04

    原文网址:http://www.oschina.net/news/51054/ubuntu-tweak-0-8-7 这是我开发 Ubuntu Tweak 七年以来第一次没在 Ubuntu 正式发布之前 ...

  10. Android Animations简介

    一 .Animations简介 Animations提供了一系列的动画效果,这些效果可以应用于绝大多数的控件: 二.Animations的分类 第一类:TweenedAnimations,该类Anim ...