CSharp 之 Attribute

前言

本篇文章旨在认识C# 中的特性,知道什么是特性,特性的作用,如何使用特性,如何自定义特性

什么是特性

特性即Attribute,可以宣告式地为自己的代码添加注解来实现某些特殊的功能。 它们的把一些附加的信息同目标关联起来,这个目标可以是类,可以是方法,可以是枚举,等等。编译器检查到代码中的特性后,会为其生成对应的元数据。

在.Net的类库中提供了非常多的特性例如比较常见的

[DllImport] 、[Serializable] 、[StructLayout]

    
如何使用特性

使用方括号,把特性名括起来放到应用的目标前方,特性类名后缀“Attribute”可以省略,例如:

[DllImport("MyLib", CharSet=CharSet.Auto, SetLastError=true)]
public static extern string GetVersion();

如果没有参数则不需要写括号。

特性的本质

特性其实就是一个类的实例,因此需要这个类至少拥有一个公共的构造函数。这个类要派生自System.Attribute

定义自己的特性类

可以把特性想像成一个逻辑状态容器,不需要很复杂,只需要一个公共构造器来接收特性的强制性(或定位性)状态信息,可提供公共字段或属性以接收特性的可选状态信息。类不应提供任何公共方法、事件或其他成员。

实际测试代码:

 如果把默认构造器私有化则会报上面的错误

设定特性的合法使用范围

告诉编译器,这个某个特性只能给某个或几个类型元素使用, 例如只能应用于Class和Method,这个时候就需要使用AttributeUsageAttribute了,这个特性作用于我们自定义的特性类,即可限制我们的自定义类的使用范围。

它有三个参数:1.目标类型(AttributeTarget) 2.是否支持重复(AllowMultiple) 3.是否可被子类继承(Inherited)

AttributeTargets是一个位标志枚举类型,见下方代码:

/// <summary>Specifies the application elements on which it is valid to apply an attribute.</summary>
  [Flags]
  [ComVisible(true)]
  [__DynamicallyInvokable]
  [Serializable]
  public enum AttributeTargets
  {
    /// <summary>Attribute can be applied to an assembly.</summary>
    [__DynamicallyInvokable] Assembly = 1,
    /// <summary>Attribute can be applied to a module.</summary>
    [__DynamicallyInvokable] Module = 2,
    /// <summary>Attribute can be applied to a class.</summary>
    [__DynamicallyInvokable] Class = 4,
    /// <summary>Attribute can be applied to a structure; that is, a value type.</summary>
    [__DynamicallyInvokable] Struct = 8,
    /// <summary>Attribute can be applied to an enumeration.</summary>
    [__DynamicallyInvokable] Enum = 16, // 0x00000010
    /// <summary>Attribute can be applied to a constructor.</summary>
    [__DynamicallyInvokable] Constructor = 32, // 0x00000020
    /// <summary>Attribute can be applied to a method.</summary>
    [__DynamicallyInvokable] Method = 64, // 0x00000040
    /// <summary>Attribute can be applied to a property.</summary>
    [__DynamicallyInvokable] Property = 128, // 0x00000080
    /// <summary>Attribute can be applied to a field.</summary>
    [__DynamicallyInvokable] Field = 256, // 0x00000100
    /// <summary>Attribute can be applied to an event.</summary>
    [__DynamicallyInvokable] Event = 512, // 0x00000200
    /// <summary>Attribute can be applied to an interface.</summary>
    [__DynamicallyInvokable] Interface = 1024, // 0x00000400
    /// <summary>Attribute can be applied to a parameter.</summary>
    [__DynamicallyInvokable] Parameter = 2048, // 0x00000800
    /// <summary>Attribute can be applied to a delegate.</summary>
    [__DynamicallyInvokable] Delegate = 4096, // 0x00001000
    /// <summary>Attribute can be applied to a return value.</summary>
    [__DynamicallyInvokable] ReturnValue = 8192, // 0x00002000
    /// <summary>Attribute can be applied to a generic parameter.</summary>
    [__DynamicallyInvokable] GenericParameter = 16384, // 0x00004000
    /// <summary>Attribute can be applied to any application element.</summary>
    [__DynamicallyInvokable] All = GenericParameter | ReturnValue | Delegate | Parameter | Interface | Event | Field | Property | Method | Constructor | Enum | Struct | Class | Module | Assembly, // 0x00007FFF
  }

AllowMultiple如果不为true,那么对于同一个目标,一个特性只能应用一次

Inherited如果是true,则会将特性应用于派生类和重写的方法

如果我们不给自定义特性添加AttributeUsage,则默认为针对所有目标元素都可以使用该特性。

让特性活起来

检测定制特性

光定义特性没用,还要定义这些特性的处理逻辑,这免不了要解决一个问题就是如何发现目标身上的特性,我们可以通过反射来实现。

System.Reflection.CustomAttributeExtensions

有三个静态方法:IsDefined、GetCustomAttributes、GetCustomAttribute

 

 后两个还支持泛型获取:

 如果只想判断某个目标是否应用了某个特性,则使用IsDefined是最优解,但如果要构造特性对象,则需要使用后面两个了。每次调用GetCustomAttribute和GetCustomAttributes的时候都会构造指定特性类型的实例,并根据源代码中的指定值来设置特性的属性。

System.Reflection定义了几个类允许检查模块的元数据,包括Assembly、Module、ParameterInfo、MemberInfo、Type、MethodInfo、ConstructorInfo、FieldInfo、EventInfo、PropertyInfo以及其各自的*Builder类,这些类都提供了IsDefined和GetCustomAttributes方法。

参考书籍:CLR via C# 第4版

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值