zoukankan      html  css  js  c++  java
  • [C#] C# 知识回顾

    C# 知识回顾 - 特性 Attribute

    【博主】反骨仔    【原文地址】http://www.cnblogs.com/liqingwen/p/5911289.html

    目录

    一、特性简介

      特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,可在运行时使用“反射”查询特性。

      特性具有以下属性:

        (1)特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。

        (2)可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。

        (3)特性可以与方法和属性相同的方式接受参数。

        (4)程序可以使用反射检查自己的元数据或其他程序内的元数据。

    二、使用特性

      特性可以放置在几乎所有的声明中(但特定的特性可能限制在其上有效的声明类型)。在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。它必须位于所应用于的元素的紧前面并与该元素在同一行。

     1     [Serializable]  //使用特性 SerializableAttribute
     2     internal class MyClass
     3     {
     4         [DllImport("user32.dll")]   //使用特性 DllImportAttribute
     5         private static extern void Do();
     6 
     7         #region 一个声明上可放置多个特性
     8 
     9         private void MethodA([In][Out]ref double n) { }
    10         private void MethodB([In, Out]ref double n) { }
    11 
    12         #endregion 一个声明上可放置多个特性
    13 
    14         #region 某些特性对于给定实体可以指定多次
    15 
    16         [Conditional("DEBUG"), Conditional("TEST1")]
    17         private void TraceMethod() { }
    18 
    19         #endregion 某些特性对于给定实体可以指定多次
    20     }

      【注意】根据约定,所有特性名称都以单词“Attribute”结束,以便将它们与“.NET Framework”中的其他项区分。但是,在代码中使用特性时,不需要指定 attribute 后缀。

    三、特性的参数

      许多特性都有参数,而这些参数可以是定位参数未命名参数命名参数。任何定位参数都必须按特定顺序指定并且不能省略,而命名参数是可选的且可以按任意顺序指定。首先指定定位参数。例如,这三个特性是等效的:

    1 [DllImport("user32.dll")] 
    2 [DllImport("user32.dll", SetLastError=false, ExactSpelling=false)] 

      第一个参数(DLL 名称)是定位参数并且总是第一个出现,其他参数为命名参数。在这种情况下,两个命名参数均默认为 false,因此可将其省略。

    四、特性的目标

      特性的目标是应用该特性的实体。例如,特性可以应用于类、特定方法或整个程序集。默认情况下,特性应用于它后面的元素。但是,您也可以显式标识要将特性应用于方法还是它的参数或返回值。

      若要显式标识特性目标,语法:

    [target : attribute-list]
    特性目标
    C# 适用对象
    assembly 整个程序集
    module 当前程序集模块
    field 在类或结构中的字段
    event event
    method 方法或 get 和 set 属性访问器
    param 方法参数或 set 属性访问器参数
    property 属性
    return 方法、属性索引器或 get 属性访问器的返回值
    type 结构、类、接口、枚举或委托

     

    //示例:将特性应用于程序集和模块
    [assembly: AssemblyTitle("assembly 4.6.1")]
    [module: CLSCompliant(true)]
     1 //示例:将特性应用于方法、方法参数和方法返回值
     2 
     3 //默认:应用于方法
     4 [SomeAttr] 
     5 int Method1() { return 0; } 
     6 
     7 //指定应用于方法
     8 [method: SomeAttr]
     9 int Method2() { return 0; } 
    10 
    11 //指定应用于返回值
    12 [return: SomeAttr] 
    13 int Method3() { return 0; }

    五、特性的常见用途

      以下列表包含特性的几个常见用途:

        (1)在 Web 服务中,使用 WebMethod 特性来标记方法,以指示该方法应该可通过 SOAP 协议进行调用。

        (2)描述当与本机代码进行交互操作时如何封送方法参数。有关更多信息。

        (3)描述类、方法和接口的 COM 属性。

        (4)使用 DllImportAttribute 类调用非托管代码。

        (5)在标题、版本、说明或商标方面描述您的程序集。

        (6)描述要持久性序列化类的哪些成员。

        (7)描述如何映射类成员和 XML 节点以便进行 XML 序列化。

        (8)描述方法的安全要求。

        (9)指定用于强制安全性的特性。

        (10)由实时 (JIT) 编译器控制优化,以便易于调试代码。

        (11)获取有关调用方的信息的方法。

     

    六、创建自定义的特性

       通过定义一个特性类,可以创建您自己的自定义特性。该特性类直接或间接地从 Attribute 派生,有助于方便快捷地在元数据中标识特性定义。

     1     /// <summary>
     2     /// 角色特性
     3     /// </summary>
     4     /// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
     5     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
     6     public class RoleAttribute : Attribute
     7     {
     8         private string _name;
     9 
    10         /// <summary>
    11         /// 启用标识
    12         /// </summary>
    13         /// IsEnable:命名参数
    14         public bool IsEnable { get; set; }
    15 
    16         /// <summary>
    17         /// 构造函数
    18         /// </summary>
    19         /// <param name="name"></param>
    20         /// name:定位参数
    21         public RoleAttribute(string name)
    22         {
    23             _name = name;
    24         }
    25     }
    1     [Role("Me", IsEnable = true)]   //调用特性的方式
    2     public class OurClass
    3     {
    4 
    5     }

      构造函数的参数是自定义特性的定位参数,任何公共的读写字段或属性都是命名参数。注意】 AttributeUsage 特性,在这里它使得 Role 特性仅在类和 struct 声明中有效。

     

    1     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]  //AllowMultiple:该值指示能否为一个程序多次使用该特性
    2     public class RoleAttribute : Attribute
    3     {
    4         //... ...
    5     }
    1     [Role("You")]            //在同一个类上多次使用
    2     [Role("Me", IsEnable = true)]   
    3     public class OurClass
    4     {
    5         //... ...
    6     }

      【注意】如果特性类包含一个属性,则该属性必须为读写属性。

     

    七、使用反射访问特性

       使用反射,可检索用自定义特性定义的信息。主要方法是 GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码特性。

     1     /// <summary>
     2     /// 角色特性
     3     /// </summary>
     4     /// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
     5     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
     6     public class RoleAttribute : Attribute
     7     {
     8         private string _name;
     9         /// <summary>
    10         /// 启用标识
    11         /// </summary>
    12         public bool IsEnable { get; set; }
    13 
    14         /// <summary>
    15         /// 构造函数
    16         /// </summary>
    17         /// <param name="name"></param>
    18         public RoleAttribute(string name)
    19         {
    20             _name = name;
    21         }
    22     }
    RoleAttribute.cs
    1     [Role("Me", IsEnable = true)]   
    2     public class OurClass
    3     {
    4         //... ...
    5     }

      概念上等效于

    1     RoleAttribute role = new RoleAttribute("Me");
    2     role.IsEnable = true;

      但是,直到查询 OurClass 来获取特性后才会执行此代码。对 OurClass 调用 GetCustomAttributes 会导致按上述方式构造并初始化一个 RoleAttribute 对象。如果该类具有其他特性,则按相似的方式构造其他特性对象。然后 GetCustomAttributes 返回 RoleAttribute 对象和数组中的任何其他特性对象。之后就可以对此数组进行迭代,确定根据每个数组元素的类型所应用的特性,并从特性对象中提取信息。

       这里,定义一个自定义特性,将其应用于若干实体并通过反射进行检索。

     1     /// <summary>
     2     /// 角色特性
     3     /// </summary>
     4     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
     5     public class RoleAttribute : Attribute
     6     {
     7         private readonly string _name;
     8 
     9         /// <summary>
    10         /// 启用标识
    11         /// </summary>
    12         public bool IsEnable { get; set; }
    13 
    14         /// <summary>
    15         /// 构造函数
    16         /// </summary>
    17         /// <param name="name"></param>
    18         public RoleAttribute(string name)
    19         {
    20             _name = name;
    21         }
    22 
    23         public string GetName()
    24         {
    25             return _name;
    26         }
    27     }
        class MyClass1 { }
    
        [Role("Me")]
        class MyClass2 { }
    
        [Role("Me"), Role("You", IsEnable = true)]
        class MyClass3 { }
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Output(typeof(MyClass1));
     6             Output(typeof(MyClass2));
     7             Output(typeof(MyClass3));
     8 
     9             Console.Read();
    10         }
    11 
    12         /// <summary>
    13         /// 输出
    14         /// </summary>
    15         /// <param name="t"></param>
    16         static void Output(Type t)
    17         {
    18             Console.WriteLine($"Class: {t}");
    19 
    20             var attributes = t.GetCustomAttributes();
    21             foreach (var attribute in attributes)
    22             {
    23                 var attr = attribute as RoleAttribute;
    24 
    25                 if (attr == null)
    26                 {
    27                     return;
    28                 }
    29 
    30                 Console.WriteLine($"    Name: {attr.GetName()}, IsEnable: {attr.IsEnable}");
    31             }
    32         }
    33     }

     

     

     

     

     

    传送门

      《只是想简单说下表达式树 - Expression Trees

      《只是想简单说下序列化


    【参考】微软官方文档

  • 相关阅读:
    html5+plus(5+app) 扫一扫(plus.barcode)
    uniapp地图控件(浅显使用)
    sku排列算法,库存类展示(规格,型号,颜色等)
    『嗨威说』数据结构中常用的查找算法思路总结
    『ACM C++』 PTA 天梯赛练习集L1 | 057-063
    『ACM C++』 PTA 天梯赛练习集L1 | 054-056
    『ACM C++』 PTA 天梯赛练习集L1 | 052-053
    『ACM C++』 PTA 天梯赛练习集L1 | 050-51
    『ACM C++』 PTA 天梯赛练习集L1 | 048-49
    『ACM C++』 PTA 天梯赛练习集L1 | 046-47
  • 原文地址:https://www.cnblogs.com/liqingwen/p/5911289.html
Copyright © 2011-2022 走看看