当前位置:主页 > 软件编程 > .NET代码 >

C#自定义特性(Attribute)详解

时间:2022-08-09 08:33:41 | 栏目:.NET代码 | 点击:

在前面介绍的代码中有使用特性,这些特性都是Microsoft定义好的,作为.NET Framework类库的一部分,许多特性都得到了C#编译器的支持。
.NET Frmework也允许定义自己的特性。自定义特性允许把自定义元数据与程序元素关联起来。这些元数据是在编译过程中创建的,并嵌入到程序集中。这些特性不会影响编译过程,因为编译器不能识别它们,但这些特性在应用于程序元素时,可以在编译好的程序集中用作元数据。这些元数据在文档说明中很有用。使自定义特性起很大作用的是反射(https://www.jb51.net/article/244259.htm)技术,代码可以读取这些元数据,使用它们在运行期间作决策。

编写自定义特性

[FieldName("Social")]
        public string SocialNumber
        {
            ...
        }

当C#编译器发现SocialNumber属性应用了一个FieldName特性时,首先会把字符串Attribute追加到FieldName这个名称后面,形成一个组合名称FieldNameAttribute,然后在其搜索路径的所有名称空间(即在using语句中提及的名称空间)中搜索FieldNameAttribute类。但如果该特性的名称以字符串Attribute结尾,编译器就不会把这个字符串加到组合名称中。
因此上面的代码等价于:

[FieldNameAttribute("Social")]
        public string SocialNumber
        {
            ...
        }

1.AttributeUsage特性

自定义的特性类需要直接或间接派生自System.Attribute。这个类还应包含控制用法的信息:

如果编译器找不到对应的特性类,或者找到一个这样的特性类,但使用特性的方式与特性类中的信息不匹配,编译器就会产生一个编译错误。
定义FieldNameAttribute特性

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
        public class FieldNameAttribute:Attribute
        {
            private string name;
            public FieldNameAttribute(string name)
            {
                this.name = name;
            }
        }

特性类FieldNameAttribute本身用了一个特性System.AttributeUsage来标记。这是Microsoft定义的一个特性,C#编译器为它提供了特殊的支持。AttributeUsage主要用于标识自定义特性可以应用到哪些类型的程序元素上。这些信息由它的第一个参数AttributeTargets给出,该参数是必选的,其类型是枚举类型AttributeTargets。上面的例子,指定FieldNameAttribute特性只能应用到属性上。
AttributeTargets枚举的成员如下:

上面列出了可以应用该特性的所有程序元素。在把特性应用到程序元素上时,应把特性放在元素前面的方括号中:

  [FieldName("Social")]
  public string SocialNumber
  {
    ...
  }

但在应用到Assembly和Module时,特性可以应用到整个程序集或模块中,而不是应用到代码中的一个元素上,在这种情况下,这个特性可以放在源代码的任何地方,但需要使用关键字Assembly和Module作为前缀:

  [assembly:FieldName("Social")]
  [module:FieldName("Social")]

在指定自定义特性的有效目标元素时,可以使用OR运算符(|)把这些值组合起来:

  [AttributeUsage(AttributeTargets.Property |AttributeTargets.Field,
    AllowMultiple=false, Inherited=false)]
  public class FieldNameAttribute:Attribute
  {
    private string name;
    public FieldNameAttribute(string name)
    {
      this.name = name;
    }
  }

也可以使用AttributeTargets.All指定自定义特性可以应用到所有类型的程序元素上。
AttributeUsage特性还包含另外两个参数:AllowMultiple和Inherited。它们用不同的语法来指定:参数名 = 参数值,而不是只给出这些参数的值。这些参数是可选的。

2.指定特性参数

  [FieldName("Social")]
  public string SocialNumber
  {
    ...
  }

编译器会检查传递给特性的参数(在本例中,是一个字符串),并产兆该特性类中带这些参数的构造函数。如果找到匹配的构造函数,编译器就会把指定的元数据传递给程序集。如果找不到,就会生成一个编译错误。反射()会从程序集中读取元数据,并实例化它们表示的特性类。因此,编译器需要确保存在这样的构造函数,才能在运行期间实例化指定的特性。

3.特性的可选参数

在AttributeUsage特性中,使用参数名 = 参数值语法把可选参数添加到特性中。这种语法指定可选参数的名称和值,它通过特性类中的公共属性或字段起作用:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
        public class FieldNameAttribute:Attribute
        {
            private string name;
            public FieldNameAttribute(string name)
            {
                this.name = name;
            }
            
            public string Comment
            {
                get;set;
            }
        }
        
        
        [FieldName("Social",Comment="可选参数值")]
        public string SocialNumber
        {
            ...
        }

您可能感兴趣的文章:

相关文章