BigBox777

爱学习、爱运动

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

阅读目录

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

posted on 2021-03-16 16:19  BigBox777  阅读(227)  评论(0编辑  收藏  举报