zoukankan      html  css  js  c++  java
  • C#技术栈入门到精通系列3——特性Attribute

    阅读目录

    1、介绍

    2、特性使用

    3、自定义特性

      3.1、自定义无参特性

      3.2、自定义有参特性

      3.3、特性类修饰AttributeUsage

    4、特性应用案例

    5、参考

    返回系列文章目录 

    1、介绍

      官方介绍:使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。 将特性与程序实体相关联后,可以在运行时使用 反射 这项技术查询特性。我个人的理解,特性就是给程序(可以是程序集、类、接口、方法、属性等等)标注一些信息,在使用的时候用反射来读取区分,进行特殊处理,使程序去耦合。可以简单理解为,特性是用来标记一种功能,在另一个地方实现这种功能。使用的时候在一个地方用[]来标注,另一个地方反射读取进行特殊处理,例如MVC、ORM、IOC容器等很多地方都是使用特性来实现。

    2、特性使用

      这里我们使用官方的Obsolete特性来介绍怎么使用的。Obsolete特性是标注一个方法已经过时了,不推荐使用。创建一个类TestClassOne,代码如下

     1 // TestClassOne.cs
     2 using System;
     3 
     4 namespace Demo02_Attribute
     5 {
     6     public class TestClassOne
     7     {
     8         [Obsolete]
     9         public void TestMethodOne(string msg)
    10         {
    11             Console.WriteLine($"TestClassOne.TestMethodOne( {msg} )");
    12         }
    13         public void TestMethodTwo(string msg)
    14         {
    15             Console.WriteLine($"TestClassOne.TestMethodTwo( {msg} )");
    16         }
    17     }
    18 }
    TestClassOne.cs

    如果你创建TestClassOne类的实例,去调用被Obsolete特性标记的TestMethodOne方法的时候,这个调用的下面会有波浪线提示这个方法是被弃用的

     1 // 使用特性
     2 namespace Demo02_Attribute
     3 {
     4     class Program
     5     {
     6         static void Main(string[] args)
     7         {
     8             TestClassOne testClassOne = new TestClassOne();
     9             testClassOne.TestMethodOne("轻轻河边草、悠悠天不老");
    10             testClassOne.TestMethodTwo("野火烧不尽、风雨吹不倒");
    11             Console.ReadKey();
    12         }
    13     }
    14 }
    使用特性

    3、自定义特性

      自定义特性分三步:编写特性类,标记特性,用反射读取特性处理。

    3.1、自定义无参特性

    1 // 创建自定义特性类
    2 using System;
    3 
    4 namespace Demo03_Attribute
    5 {
    6     public class CustomOneAttribute: Attribute
    7     {
    8     }
    9 }
    创建自定义特性类
     1 // 标记使用特性
     2 namespace Demo03_Attribute
     3 {
     4     [CustomOneAttribute] //可以简写[CustomOne]
     5     public class Student
     6     {
     7         [CustomOne]
     8         public string Name { get; set; }
     9         public int Age { get; set; }
    10         [CustomOne]
    11         public void Sing()
    12         {
    13         }
    14         public void Say()
    15         {
    16         }
    17     }
    18 }
    标记使用特性
     1 // 使用反射读取被特性标记的类、方法、属性
     2 using System;
     3 
     4 namespace Demo03_Attribute
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Student student = new Student();
    11             var type = student.GetType();
    12             //看看类是否被特性标记
    13             if(type.IsDefined(typeof(CustomOneAttribute),true))
    14             {
    15                 //拿去被标记的特性
    16                 var attributeArr = type.GetCustomAttributes(typeof(CustomOneAttribute), true);
    17                 foreach (var attr in attributeArr)
    18                 {
    19                     //attr就是每个标记的自定义特性CustomOneAttribute
    20                     
    21                 }
    22 
    23             }
    24 
    25             //遍历查找被自定义特性标记的方法
    26             foreach (var method in type.GetMethods())
    27             {
    28                 if (method.IsDefined(typeof(CustomOneAttribute), true))
    29                 {
    30                     //method就是被自定义特性标记的
    31                     var attributeArr = method.GetCustomAttributes(typeof(CustomOneAttribute), true);
    32                     foreach (var attr in attributeArr)
    33                     {
    34                         //attr就是每个标记的自定义特性CustomOneAttribute
    35 
    36                     }
    37                 }
    38             }
    39 
    40             //遍历查找被自定义特性标记的属性
    41             foreach (var prop in type.GetProperties())
    42             {
    43                 if (prop.IsDefined(typeof(CustomOneAttribute), true))
    44                 {
    45                     //prop就是被自定义特性标记的
    46                     var attributeArr = prop.GetCustomAttributes(typeof(CustomOneAttribute), true);
    47                     foreach (var attr in attributeArr)
    48                     {
    49                         //attr就是每个标记的自定义特性CustomOneAttribute
    50 
    51                     }
    52                 }
    53             }
    54 
    55             Console.ReadKey();
    56         }
    57     }
    58 }
    使用反射读取被特性标记的类、方法、属性

    3.2、自定义有参特性

      向上面这样标记一个特性,通过反射去读取,然后找出来编写附件功能,这样太单一(一个特性只能标记一种),我们还可以把参数保存在特性类中,这样即使标记了同一种特性,也可以根据参数不同而差异化处理。例如下面。

     1 // 创建有参数特性
     2 using System;
     3 namespace Demo03_Attribute
     4 {
     5     public class CustomTwoAttribute:Attribute
     6     {
     7         public int age;
     8         private string _name;
     9         public CustomTwoAttribute(string name)
    10         {
    11             this._name = name;
    12         }
    13     }
    14 }
    创建有参数特性
     1 // 标记使用特性
     2 namespace Demo03_Attribute
     3 {
     4     public class Animal
     5     {
     6         [CustomTwoAttribute("甜美",age = 7)]
     7         public void Jump()
     8         {
     9         }
    10     }
    11 }
    标记使用特性
     1 // 使用反射把特性属性读出来
     2 using System;
     3 
     4 namespace Demo03_Attribute
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Animal animal = new Animal();
    11             var type = animal.GetType();
    12             foreach (var method in type.GetMethods())
    13             {
    14                 if (method.IsDefined(typeof(CustomTwoAttribute), true))
    15                 {
    16                     //method就是被自定义特性标记的
    17                     var attributeArr = method.GetCustomAttributes(typeof(CustomTwoAttribute), true);
    18                     foreach (var attr in attributeArr)
    19                     {
    20                         //attr就是每个标记的自定义特性CustomTwoAttribute
    21                         CustomTwoAttribute customTwoAttribute = (CustomTwoAttribute)attr;
    22                         
    23                     }
    24                 }
    25             }
    26 
    27             Console.ReadKey();
    28         }
    29     }
    30 }
    使用反射把特性属性读出来

    3.3、特性类修饰AttributeUsage

      有的场合,我们定义的特性只能给特定的对象用,比如类、方法、属性这样分类的,这个时候,我们就需要限制自定义特性使用的环境,这个时候就需要使用 AttributeUsage 来标记自定义特性了。 

    例如:[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]   //这个特性只能标记在类上面,具有继承性,允许同时标记多次

     1 // 特性修饰
     2 using System;
     3 namespace Demo03_Attribute
     4 {
     5     //AttributeTargets指定这个特性能修饰程序的哪部分
     6     //Inherited指定这个特性子类也被继承
     7     //AllowMultiple允许重复修饰
     8     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
     9     public class CustomThreeAttribute:Attribute
    10     {
    11     }
    12 }
    特性修饰

    4、特性应用案例

      看了上面的内容你肯定会感觉空洞乏味,不知所云,是不是向问一句,有没有实际的案例举一个呢。现在举个简单的案例,比如有的时候,我们后台定义枚举类型来定义员工的职位(general manager, director, manager, supervisor, employee),前台显示的时候,需要显示一些更具有亲和力的称呼(总经理、总监、经理、主管、员工)

     1 // 定义job特性
     2 using System;
     3 
     4 namespace Demo03_Attribute
     5 {
     6     [AttributeUsage(AttributeTargets.Field)]
     7     public class JobAttribute: Attribute
     8     {
     9         private string _job;
    10         public string Job {
    11             get { return _job; }
    12         }
    13         public JobAttribute(string job)
    14         {
    15             this._job = job;
    16         }
    17     }
    18 }
    定义job特性
     1 // 后台枚举类中标记Job特性
     2 namespace Demo03_Attribute
     3 {
     4     public enum EnumJob
     5     {
     6         [Job("总经理")]
     7         GeneralManager,
     8         [Job("总监")]
     9         Director,
    10         [Job("经理")]
    11         Manager,
    12         [Job("主管")]
    13         Supervisor,
    14         [Job("员工")]
    15         Employee
    16     }
    17 }
    后台枚举类中标记Job特性
     1 // 新建特性扩展,用来转换
     2 namespace Demo03_Attribute
     3 {
     4     public class AttributeExtend
     5     {
     6         public static string GetJob(EnumJob value)
     7         {
     8             var type = value.GetType();
     9             var field = type.GetField(value.ToString());
    10             if (field.IsDefined(typeof(JobAttribute), true)){
    11                 JobAttribute jobAttribute = (JobAttribute)field.GetCustomAttribute(typeof(JobAttribute), true);
    12                 return jobAttribute.Job;
    13             }
    14             return value.ToString();
    15         }
    16     }
    17 }
    新建特性扩展,用来转换
    1 // 前台获取
    2 var job = EnumJob.Employee;
    3 var jobName = AttributeExtend.GetJob(job);
    4 Console.WriteLine($"{job}:{jobName}");
    前台获取

    5、参考

    特性 (C#)  https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/

    创建自定义特性 (C#)  https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/creating-custom-attributes

    编写自定义特性  https://docs.microsoft.com/zh-cn/dotnet/standard/attributes/writing-custom-attributes

    使用反射访问特性 (C#)  https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/accessing-attributes-by-using-reflection

    检索存储在特性中的信息  https://docs.microsoft.com/zh-cn/dotnet/standard/attributes/retrieving-information-stored-in-attributes

    利用特性扩展元数据  https://docs.microsoft.com/zh-cn/dotnet/standard/attributes/

    C# 保留的特性:Conditional, Obsolete, AttributeUsage  https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/attributes/general

    C# 保留的特性:跟踪调用方信息  https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/attributes/caller-information

  • 相关阅读:
    MySQL 慢日志没有自动创建新的日志文件
    Springboot为什么加载不上application.yml的配置文件
    android studio set proxy
    c++ win32 遍历进程列表
    React Prompt组件 阻止用户离开页面
    JS 浏览器上生成 UUID API
    部署 Nestjs 最佳实践
    Nginx 部署 单页面应用 + nodejs api 应用 最佳实践
    React JS: 如何使用 RxService 管理状态
    umijs 开发优化和生产优化
  • 原文地址:https://www.cnblogs.com/bigbox777/p/14414491.html
Copyright © 2011-2022 走看看