特性

特性

               C#允许开发人员以特性(attribute)的形式为程序添加说明性信息。特性定义了与类、结构、方法等相关的附加信息(元数据)。例如,可以定义一个特性来制定该类中将要现实的按钮的类型。特性包含在所应用想之前的方括号“[]”中,因此它不是类得成员,而仅仅是该项的附加信息。

              1. 特性基础

                 特性由System.Attribute的派生类来支持。因此,所有的特性类必须是Attribute类得子类。尽管Attribute类定义了大量的功能,但是用特性时一般不会用到全部的功能。按照惯例,特性类名通常是用后缀Attribute。例如,ErrorAttribute是一个描述错误的特性类的名称。

                在声明特性类时,前面应加上AttributeUsage特性。这个内置特性指明了该特性适用的项的类型。例如,把特性限定为进攻方法适用。

              2. 创建特性

                在特性类中,可以定义支持该特性的成员。特性类通常非常简单,只包含少量的字段或属性(property)。例如,特性可以定义一个符号,用于描述应用此特性的项。这种特性的声明如下所示:

            

 [AttributeUsage(AttributeTargets.All)]
    public class RemberAttribute : Attribute
    {
        string pri_remark;
        public RemberAttribute(string comment)
        {
            pri_remark = comment;
        }
        public string Remark
        {
            get{return pri_remark;}
        }
    }
        

          该类的名称为 RemarkAttribute,类得声明语句之前有 AttributeUsage特性,它指明RemarkAttribute能够应用于所有类型的项。通过使用AttributeUsage ,可以限制应用特性的项类型。

         接下来,声明RemarkAttribute,它继承Attribute类。在RemberAttribute中只有一个私有字段pri_remark,用于支持公共的只读属性 Remark 。 此属性用于保存与该特性相关的描述。RemarkAttribute只有一个公共的构造函数,该构造函数带有一个字符串参数。参数被赋值给Remark.

       3.  连接特性

            一旦定义了特性类,就可以把它连接到项上。可以把特性放置在应用它的项之前,并且通过把它的构造函数包含在方括号中来指示。

                  

    [Rember("this class uses an attribute.")]
    public class UseAttrib { 
    
     //...    
    }
       

这里只使用了名称Remark。尽管这种方式是正确的,但在连接特性时使用全称会更加安全,因为这样可以避免可能产生的混乱和歧义。

       4.获取对象的特性

           一旦吧特性连接到项上,程序的其他部分就能获取该特性。为了获取特性,通常需要使用下面两个方法之一。

第一个方法是GetCustomAttributes(),它由MemberInfo类定义并且被Type类继承。此方法可以获取连接到某个项的所有特性的列表。

它的基本形式为:   object[] GetCustomAttribute(bool searchBases)

如果searchBases为真,那么继承链中所有基类的特性都会被包含进来。否则,就只获取指定类型本身定义的特性。

第二个方法是由Attribute定义的GetCustomAttribute(),它的一种形式为:

static Attribute GetCustomAttribute(MembetInifo mi,Type attribtype)

其中,mi是一个MemberInfo类型的对象,它描述了要获得那个项的特性。希望获得的特性由Attribtype指定。如果一直想要获得的特性的名称,可以使用此方法。

 [AttributeUsage(AttributeTargets.All)]
    public class RemarkAttribute : Attribute
    {
        string pri_remark;
        public RemarkAttribute(string comment)
        {
            pri_remark = comment;
        }
        public string Remark
        {
            get { return pri_remark; }
        }
    }

    [Remark("this class uses an attribute.")]
    public class UseAttrib
    {
    }

    class NTest
    {
        static void Main(string[] args)
        {
            Type t = typeof(UseAttrib);
            Console.Write("Attributes in " + t.Name + ": ");
            object[] attribs = t.GetCustomAttributes(false);
            foreach (object o in attribs)
            {
                Console.WriteLine(o);
            }
            Console.Write("Remark:");

            Type tRemAtt=typeof(RemarkAttribute);
            RemarkAttribute ra=(RemarkAttribute) Attribute.GetCustomAttribute(t,tRemAtt);
            Console.WriteLine(ra.Remark);

            Console.Read();
        }
    }

位置参数和命名参数

          当调用特性的构造函数时,可以使用两种方式的参数,一种为位置参数,另一种为命名参数 。

位置参数与普通的方法调用方式一样,命名参数则为:

[Remark("this class uses an attribute.",name="str")]

命名参数由公共字段或属性来支持,它们必须可读写并且是非静态的。

在使用的时候,首先定义位置参数(如果存在的话),然后是每一个命名参数的赋值语句。命名参数的顺序并不重要,它们的初始值也不必给出。为给定初始值时,参数将使用默认值。


三个内置特性

            C#定义了多个内置特性,其中最重要的3个是AttributeUsage、Conditioinal和Obsolete。这些特性在很多场合都会用到。

                1. AttributeUsage特性

                       AttributeUsage特性指定了能够应用该特性的项的类型。AttributeUsage是System.AttributeUsageAttribute类得别名,它的构造函数为:

                       AttributeUsage(AttributeTargets item)

       AttributeUsage枚举定义表:如下

AllAssembly
Class
Constructor
Delegate
Enum
Event
Field
GenericParameter
Interface
Method
Module
Parameter
Property
ReturnValue
Struct

可以将这些值中的两个或多个执行OR运算。例如,为了指定一个智能应用于字段和属性的特性,则使用: AttributeTargets.Field | AttributeTargets.Property

AttribyteUsage支持两个命名参数。第一个是AllowMultiple,它是一个bool值。如果该值为真,那么这个特性就能够多次应用于单个项。第二个是Inherited,它也是一个bool值。如果钙质为真,那么该特性可以被派生类继承,否则就不能被继承。一般地,AllowMultiple的默认值为假,而Inherited的默认值为真。

            AttribyteUsage还指定了一个只读属性ValidOn,该属性返回一个AttributeTargets类型的值来说明可以应用该特性的项的类型。其默认值为AttributeTargets.All。

          2.Conditional特性

           Conditional或许是C#中最有趣的内置特性。它允许开发人员创建条件方法(conditional methods).条件方法只有在通过#define定义了特定的符号时才能被调用。否则,方法将被忽略。因此,条件方法可以取代使用#if条件编译命令。

            Conditional是System.Diagnostics.ConditionalAttribute的别名。要使用Conditional特性,必须先包含System.Diagnostics名称空间。

#define TRIAL
using System;
using System.Reflection;
using System.Diagnostics;
namespace work
{
    class Test
    {
        [Conditional("TRIAL")]
        public void Trial()
        {
            Console.WriteLine("Trial version,nont for distributton.");
        }
        [Conditional("RELEASE")]
        public void Release()
        {
            Console.WriteLine("Final release version.");
        }
        static void Main(string[] args)
        {
            Test test = new Test();
            test.Trial();
            test.Release();
            Console.Read();
        }
    }
}
程序定义了符号TRIAL。Trial()和Release()方法。这两个方法都使用了Conditional特性,其基本形式为:

[Conditional(symbol)] 

其中,symbol是决定是否执行该方法的符号。主意这个特性只能用于方法。如果symbol已经被定义,方法在被调用时就会执行。如果未定义此符号,则不执行相应的方法。


条件方法也有一些限制:它们必须返回void ,必须是类或结构的成员而不能使接口,以及不能使用override关键组织作为前缀。



3. Obsolete特性

          Obsolete特性时System.ObsoleteAttribute的简写形式,它可以把程序中的元素标记为废弃的。

            其基本形式为:

                        [Obsolete("message")]

            编译该程序元素时将显示message。下面给出一个简短实例:

         

  class Test
    {
        [Obsolete("Use MyMeth2,instead.")]
        public static int MyMeth(int a, int b)
        {
            return a / b;
        }
        public static int MyMeth2(int a, int b)
        {
            return b == 0 ? 0 : a / b;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("4 / 3 is " + Test.MyMeth(4, 3));
            Console.WriteLine("4 / 3 is " + Test.MyMeth2(4, 3));
            Console.Read();
        }
    }

编译此程序时,如果在Main()中遇到对MyMeth()的调用,那么将产生一个警告,建议用户使用MyMethod2()方法。

Obsolete的第二种形式如下:

 [Obsolete("messsage",error)]

其中,error是一个布尔值。如果它为真,使用废弃项时,将产生编译错误而不是警告。错误与警告的区别在于,包含错误的程序不能被编译成可执行程序。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值