C# 特性(Attribute)

Attributes provide a powerful method of associating metadata, or declarative information, with code (assemblies, types, methods, properties, and so forth).After an attribute is associated with a program entity, the attribute can be queried at run time by using a technique called reflection.
定制特性(Custom attribute)本质上是一个类型的实例。定制特性类必须直接或间接从公共抽象类System.Attribute派生。它是类的实例,在编译时被序列化成驻留在元数据中的字节流。在运行时,可对元数据进行反序列化,从而构造出类的实例。
特性有公共构造函数,且允许设置与特性类关联的公共字段或属性。构造器的参数称为定位参数(positional parameter),是强制性的(必选);用于设置字段或属性的“参数”称为命名参数(named parameter),是可选的。可将多个特性应用于一个目标元素,特性的顺序无关紧要。
[DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    [assembly: SomeAttr]         // Applied to assembly
    [module: SomeAttr]           // Applied to module
    [type: SomeAttr]             // Applied to type
    sealed class SomeType<[typevar: SomeAttr] T> // Applied to generic type variable
    { 
        [field: SomeAttr]        // Applied to field
        public int SomeField = 0;

        [return: SomeAttr]       // Applied to return value
        [method: SomeAttr]
        public int SomeMethod(
            [param: SomeAttr]    // Applied to parameter
            int SomeParam)
        {
            return SomeParam;
        }

        [property: SomeAttr]     // Applied to property
        public string SomeProp {
            [method: SomeAttr]   // Applied to get accessor method
            get { return null; }
        }

        [event: SomeAttr]        // Applied to event
        [field: SomeAttr]        // Applied to compiler-generated field
        [method: SomeAttr]       // Applied to compiler-generated add & remove methods
        public event EventHandler SomeEvent;
    }

可以利用特性对代码进行说明(注释)或在代码设计或调试期间辅助开发。

一、条件特性

#define BUGED
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics; 
 
namespace MyAttribute
{
    public class Program   
    {
        static void Main(string[] args)
        {           
            ToolKit.FunA();         
            ToolKit.FunB();            
            ToolKit.FunC();          
            ToolKit.FunD();

            Console.ReadKey();
        }   
    }  
 
    class ToolKit   
    {     
        [ConditionalAttribute("X")] // Attribute名称的长记法   
        [ConditionalAttribute("BUGED")]     
        public static void FunA()    
        {         
            Console.WriteLine("Created By X, Buged.");   
        }      
       
        [Conditional("X")] // Attribute名称的短记法   
        [Conditional("NOBUG")]       
        public static void FunB()      
        {          
            Console.WriteLine("Created By X, NoBug.");   
        }       
      
        [Conditional("Y")]     
        [Conditional("BUGED")]
        public static void FunC()    
        {        
            Console.WriteLine("Created By Y, Buged.");      
        }

        [Conditional("Y"), Conditional("NOBUG5")]  
        public static void FunD()    
        {          
            Console.WriteLine("Created By Y, NoBug.");     
        }   
    }
}

二、定制自己的特性  

可以将特性想像成逻辑状态容器。特性类应该很简单,只提供一个公共构造器来接受特新的强制性(或定位性)状态信息,可以提供公共字段或属性以接受可选(或命名)状态信息。

// 自定义特性类
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
internal class TestAttribute : Attribute
{
}
[Test]
[Serializable]
internal class BaseType
{
    [Test]
    protected virtual void DoSomething() { }
}
internal class DerivedType : BaseType
{
    protected override void DoSomething() { }
}

如果自定义特性类时没有使用AttributeUsageAttribute, 编译器和CLR将假定该特性能应用于所有目标元素,而且可以继承。

AttributeUsageAttribute实现http://referencesource.microsoft.com/#System,namespaces

// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** Class:  AttributeUsageAttribute
**
**
** Purpose: The class denotes how to specify the usage of an attribute
**          
**
===========================================================*/
namespace System {
 
    using System.Reflection;
    /* By default, attributes are inherited and multiple attributes are not allowed */
[Serializable]
    [AttributeUsage(AttributeTargets.Class, Inherited = true)]
[System.Runtime.InteropServices.ComVisible(true)]
    public sealed class AttributeUsageAttribute : Attribute
    {
        internal AttributeTargets m_attributeTarget = AttributeTargets.All; // Defaults to all
        internal bool m_allowMultiple = false; // Defaults to false
        internal bool m_inherited = true; // Defaults to true
    
        internal static AttributeUsageAttribute Default = new AttributeUsageAttribute(AttributeTargets.All);
 
       //Constructors 
        public AttributeUsageAttribute(AttributeTargets validOn) {
            m_attributeTarget = validOn;
        }
       internal AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited) {
           m_attributeTarget = validOn;
           m_allowMultiple = allowMultiple;
           m_inherited = inherited;
       }
    
       
       //Properties 
        public AttributeTargets ValidOn 
        {
           get{ return m_attributeTarget; }
        }
    
        public bool AllowMultiple 
        {
            get { return m_allowMultiple; }
            set { m_allowMultiple = value; }
        }
    
        public bool Inherited 
        {
            get { return m_inherited; }
            set { m_inherited = value; }
        }
    }
}
 

AttributeTargets实现http://referencesource.microsoft.com/#System,namespaces

// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==


namespace System {
    
    using System;
    
    // Enum used to indicate all the elements of the
    // VOS it is valid to attach this element to.
[Serializable]
    [Flags]
[System.Runtime.InteropServices.ComVisible(true)]
    public enum AttributeTargets
    {
        Assembly      = 0x0001,
        Module        = 0x0002,
        Class         = 0x0004,
        Struct        = 0x0008,
        Enum          = 0x0010,
        Constructor   = 0x0020,
        Method        = 0x0040,
        Property      = 0x0080,
        Field         = 0x0100,
        Event         = 0x0200,
        Interface     = 0x0400,
        Parameter     = 0x0800,
        Delegate      = 0x1000,
        ReturnValue   = 0x2000,
        //@todo GENERICS: document GenericParameter
        GenericParameter = 0x4000,
        
        
        All           = Assembly | Module   | Class | Struct | Enum      | Constructor | 
                        Method   | Property | Field | Event  | Interface | Parameter   | 
                        Delegate | ReturnValue | GenericParameter,
    }
}<span style="font-size:18px;">
</span>

参考:《CLR via C#》
后面补充对反射的利用检测定制特性



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值