• C# 中的特性


    一、概念

    • 特性是一种允许我们向程序的程序集添加元数据的语言结构。它是用于保存程序结构信息的特殊类型的类。(可以通过反射来访问元数据,从而操作特性相关内容)
    • 特性类似于一种声明性标签,可以用于修饰各种元素,包括类,方法,结构体,枚举,属性,变量等。

    二、定义

    • 由方括号,特性名和参数列表构成,特性标签会被放在需要被修饰的元素之前。
    • 在一个元素上,可以使用一个或多个特性进行修饰。
    • 特性可以拥有参数。
    • 程序可以使用反射检查自己的元数据或者其他程序中的元数据。

    三、示例

    • 单个特性修饰类
    [Serializable]	//可序列化
    public class MyClass
    {
    }
    
    • 1
    • 2
    • 3
    • 4

    自定义特性类时需要主要它的三个参数

    • AttributeTargets 是标注当前特性可用于哪些对象,因为该枚举的值 在二进制中均只有一位为1, 即为2的次方整数值,所以通常通过位运算 或 ( | )来运算。

    • Inherited 表示特性是否可被 修饰类型的派生类继承。

    • AllowMultiple 表示是否可以对同一个目标进行多次修饰。

    • 自定义特性类

    	//自定义特性类
        [AttributeUsage(AttributeTargets.All)]  //用于标注当前声明的类应用于哪些对象,All表示全部对象
        public class MyDemoAttribute: Attribute
        {
            public string Description { get; set; }
        }
        
        public class OrderData
        {
            [MyDemo(Description = "订单 ID")]
            public int OrderID { get; set; }
    
            [MyDemo(Description = "添加时间")]
            public DateTime AddTime { get; set; }
    
            [MyDemo(Description = "计算折扣价")]
            public double Compute(double q)
            {
                return q * 0.8;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 向特性类构造函数传递参数
    	//向特性类构造函数传递参数
        //特性类只有无参构造,应用时可以忽略小括号。若有有参构造函数,那么应在小括号中添上参数
        [AttributeUsage(AttributeTargets.Class)]
        public class DoubleRangeAttribute: Attribute
        {
            public double Largest { get; }
    
            public DoubleRangeAttribute(double largest)
            {
                Largest = largest;
            }
        }
    
        [DoubleRange(800)]
        public class Test1
        {
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 同一对象上应用多个特性实例
    	//同一对象上应用多个特性实例(AllowMultiple默认为false)
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
        class CustomAttribute: Attribute
        {
            public string Version { get; set; }
        }
    
        //两种写法
        [Custom(Version = "1.0.0.1"), Custom(Version = "1.0.0.2")]
        [Custom(Version = "1.0.0.3")]
        public class Test2
        {
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 通过反射进行数据验证处理
        // 声明特性类
        [AttributeUsage(AttributeTargets.Property)]
        public class MyAttribute: Attribute
        {
            public char StartChar {  get; set; }
            public int MaxLen { get; set; }
        }
    
    	//被测试的类
        public class Test3
        {
            [My(StartChar = 'G', MaxLen = 10)]
            public string Name { get; set; }
        }
    
    	internal class Program
        {
            static void Main(string[] args)
            {
                func1();
            }
    
            static void func1()
            {
            	// 实例化并初始化
                Test3 test3 = new Test3 { Name = "Gzy" };
    			// 检查
                bool b = checkTest(test3, nameof(Test3.Name));
    
                if (b) Console.WriteLine("验证通过");
            }
    
    		/// 
            /// 检查传入的名字在元数据中 是否合法 包括以下3点:
            /// 判断名字是否存在
            /// 判断名字是否以StartChar字段开头
            /// 判断名字长度是否小于MaxLen字段
            /// 
            /// Test3 类型对象
            /// 需要判断的字符串
            /// 是否合法
            static bool checkTest(Test3 t, string name)
            {
                Type type = t.GetType();
    
                //名字为name的获取属性
                PropertyInfo prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
                if (prop == null)
                {
                    return false;
                }
                // 获取特性
                MyAttribute att = prop.GetCustomAttribute<MyAttribute>();
    
                //获取实例的属性值
                string value = prop.GetValue(t) as string;
    
                if (string.IsNullOrEmpty(value) //判空
                || value.StartsWith(att.StartChar.ToString()) == false  //判断首字母
                || value.Length > att.MaxLen)   //判断长度
                {
                    return false;
                }
                return true;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 在返回值上应用特性
        [AttributeUsage(AttributeTargets.ReturnValue)]
        public class CheckSumAttribute: Attribute
        {
    
        }
    
        public class Test4
        {
            [return: CheckSum]
            static string Speak() => "HelloWorld";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    SpringMVC处理ajax请求
    图像分类(二) 全面解读复现ZFNet
    新闻管理系统(SpringBoot+Vue)
    C++ STL标准模板库(一)
    JPA联合主键
    菜单组件Menu
    无感验证案例:工商联人才中心
    信息科技风险管理:合规管理、技术防控与数字化
    嵌入式Linux驱动开发(同步与互斥专题)(二)
    RS485协议和Modbus协议有什么区别?工业网关能用吗?
  • 原文地址:https://blog.csdn.net/KamikazePilot/article/details/128010216