zoukankan      html  css  js  c++  java
  • 03.特性Attribute

    1. 基本了解

    1.1 简述说明

    特性(Attribute)本质上是一个类,此类需要直接或间接继承 Attribute 类,特性为目标元素(比如类、方法、结构、枚举、组件等)提供关联附加信息,并在运行期以反射的方式来获取附加信息

    说明:特性类的实例里没有验证逻辑,只有验证用到的规范数据(比如字符串长度)、提示信息等,而验证逻辑需要自己写

    .Net 框架提供了两种类型的特性:预定义特性和自定义特性

    1.2 特性应用

    添加额外信息

    可以使用特性附加需要的信息,例如:字段的中文名,实体字段对应数据表字段的名称

    示例:Table 特性,指定表名,Route 指定路由路径

    其它功能

    例如,信息的效验,功能标识

    示例:值的长度效验,类型效验等(Model验证就是很好的例子)

    2. 特性限定

    2.1 AttributeUsage 限定

    AttributeUsageAttributeAttribute,用户指定特性使用限制,常用的有:AttributeTargetsAllowMultiple

    2.2 AttributeTargets 目标限定

    使用 AttributeTargets 表示指定Attribute限制用于哪类实体上,在这里,实体是指: classmethodconstructorfieldpropertyGenericParameter或者用All,表明可用于所有实体

    每个target标记可以用|链接(组合),如AttributeTargets.Class|AttributeTargets.Method表示可用于class或者method上,以此为例

    示例:无限定

    [AttributeUsage(AttributeTargets.All)]
    public class AllTargetsAttribute : Attribute {}
    

    示例:限定只能标记在类上

    [AttributeUsage(AttributeTargets.Class)]
    public class ClassTargetAttribute : Attribute {}
    

    示例:限定只能标记在方法上

    [AttributeUsage(AttributeTargets.Method)]
    public class MethodTargetAttribute : Attribute {}
    
    [AttributeUsage(AttributeTargets.Method,AllowMultiple = true)]
    public class MethodTargetAttribute : Attribute {}
    

    示例:限定只能标记在构造函数上

    [AttributeUsage(AttributeTargets.Constructor)]
    public class ConstructorTargetAttribute : Attribute {}
    

    示例:限定只能标记在字段上

    [AttributeUsage(AttributeTargets.Field)]
    public class FieldTargetAttribute : Attribute {}
    

    示例:限定只能标记在泛型类型参数上

    [AttributeUsage(AttributeTargets.GenericParameter)]
    public class GenericParameterTargetAttribute : Attribute {}
    

    示例:限定标记在类与方法上

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class MethodAndClassTargetAttribute : Attribute {}
    

    2.2 AllowMultiple 重复限定

    使用 AllowMultiple 表示是否可以多次标记在同一目标上,不指定默认 true

    [AttributeUsage(AttributeTargets.Method,AllowMultiple = true)]
    public class CustomAttribute : Attribute {}
    

    3. 自定义特性

    3.1 自定义步骤

    • 声明自定义特性,创建类
    • 构建自定义特性,写逻辑,功能
    • 在目标程序元素上应用自定义特性
    • 通过反射访问特性,调用特性逻辑,功能

    3.2 定义特性

    基本定义

    一个新的自定义特性应派生(继承)自 System.Attribute

    public class CustomAttribute : Attribute
    {
    	...
    }
    

    带构造函数定义,类中默认有个无参构造方法

    public class CustomAttribute : Attribute
    {
        public CustomAttribute()
        {
            Console.WriteLine("调用子类无参构造函数");
        }
        public CustomAttribute(string text)
        {
            Console.WriteLine("调用子类有参构造函数:"+text);
        }
    }
    

    带属性特性定义

    public class CustomAttribute : Attribute
    {
        public int index { get; set; }
    }
    

    带字段特性定义

    public class CustomAttribute : Attribute
    {
        public string name;
    }
    

    3.3 标记使用

    标记在类上

    [CustomAttribute]
    public class Studen
    {
        ...
    }
    

    标记在方法上

    public class Studen
    {
        [CustomAttribute]
        public void Show() { }
    }
    

    标记在属性上

    public class Studen
    {
        [CustomAttribute]
        public int id { get; set; }
    }
    

    标记在字段上

    public class Studen
    {
        [CustomAttribute]
        public int no;
    }
    

    标记在构造函数上

    public class Studen
    {
        [CustomAttribute]
        public Studen()
        {
    
        }
    }
    

    标记在方法返回参数上

    public class Studen
    {
        [return:CustomAttribute]	// 多个特性逗号隔开
        public void Show()
        {
    
        }
    }
    

    4. 综合示例

    4.1 定义特性

    定义验证特性,使用抽象(类)特性实现扩展,实现逻辑在Validate方法中

    public abstract class AbstractValidateAttribute : Attribute
    {
        public abstract bool Validate(object oValue);
    }
    
    // 验证值长度
    public class LengthAttribute : AbstractValidateAttribute
    {
        public long Max { get; set; }
        public long Min { get; set; }
        public override bool Validate(object oValue)
        {
            return oValue != null && long.TryParse(oValue.ToString().Length.ToString(), out long lValue) 
                && lValue >= Min && lValue <= Max;
        }
    }
    
    // 验证非空
    public class NullAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null;
        }
    }
    

    4.2 使用特性

    public class Studen
    {
        [NullAttribute]
        [LengthAttribute(Max =10,Min =5)]
        public string name { get; set; }
    }
    

    4.3 调用特性

    缺陷:需要手动调用扩展方法,且扩展方法没有限制,功能单一(只能用于验证)

    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t) where T : class
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            { 
                // 这里先判断,是为了提高性能
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object ovale = prop.GetValue(t);
                    // 获取特性的实例,上面先判断之后,再获取实例
                    foreach (AbstractValidateAttribute attribute 
                        in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true))
                    {
                        if (!attribute.Validate(ovale))
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
    }
    

    4.4 测试使用

    static void Main(string[] args)
    {
        Studen stu = new Studen
        {
            name = "起舞在人间"
        };
    
        Console.WriteLine(stu.Validate());
    }
    

    5. 扩展补充

    特性编译后内容

    通过反编译工具得知,标记特性的元素,最终会在元素内部生成.custom的元素

    .class public auto ansi beforefieldinit ConsoleApp2.Studen
    	extends [mscorlib]System.Object
    {
    	// Methods
    	.method public hidebysig 
    		instance void Show () cil managed 
    	{
    		.custom instance void ConsoleApp2.CustomAttribute::.ctor() = (
    			01 00 00 00
    		)
    		// Method begins at RVA 0x2085
    		// Code size 2 (0x2)
    		.maxstack 8
    
    		IL_0000: nop
    		IL_0001: ret
    	} // end of method Studen::Show
    
    	.method public hidebysig specialname rtspecialname 
    		instance void .ctor () cil managed 
    	{
    		// Method begins at RVA 0x2088
    		// Code size 8 (0x8)
    		.maxstack 8
    
    		IL_0000: ldarg.0
    		IL_0001: call instance void [mscorlib]System.Object::.ctor()
    		IL_0006: nop
    		IL_0007: ret
    	} // end of method Studen::.ctor
    
    } // end of class ConsoleApp2.Studen
    

    特性,内部属性

    在特性中声明属性,且此属性只能用于外部访问,内部赋值

    public int text { get; private set; }
    

    特性应使用构造函数赋值还是使用属性

    当属性为必填时使用构造函数,选填时使用属性赋值

    // 验证最大长度时,最大长度必填,
    [AttributeUsage(AttributeTargets.Property)]
    public class MaxLenAttribute : Attribute
    {
        public int length { get; private set; }
        public string remark { get; set; }
        public MaxLenAttribute(int len)
        {
            this.length = len;
        }
        public bool Validate(object oValue)
        {
            return oValue.ToString().Length > this.length;
        }
    }
    
    public class User
    {
        [MaxLenAttribute(5, remark = "超出长度!")]
        public string name { get; set; }
    }
    
    到达胜利之前无法回头!
  • 相关阅读:
    Kibana
    Filebeat使用
    leetcode刷题笔记七十三题 矩阵置零
    leetcode刷题笔记七十二题 编辑距离
    leetcode刷题笔记七十一题 简化路径
    leetcode刷题笔记七十题 爬楼梯
    leetcode刷题笔记六十九题 X的平方根
    python 冒泡算法
    hive 函数
    Task07:类、对象与魔法方法(3天)
  • 原文地址:https://www.cnblogs.com/weiyongguang/p/15110380.html
Copyright © 2011-2022 走看看