14特性

使用场景

框架中:类上面、方法上面、属性上面、字段上面、参数里面.....

特性本质

就是一个类,继承自Attribute类

自定义特性

直接继承Attribute类即可
public class TableAttribute:Attribute

配置特性的使用范围

通过AttriibuteUsage特性来配置我们创建的特性
参数1:使用AttributeTargets枚举作为参数,表示该特性可以使用的位置,AttributeTargets.Class表示该特性只能使用在类上面。
参数2:AllowMultiple:表示一个特性是否能有多个构造方法,指的是同一个特性能否在一个类上面使用两次,如:

我们创建一个像rom框架那样可以获取我们写在类上面做数据迁移的数据表表名如:

/// <summary>
    /// 获取表名特性
    /// </summary>
   [AttributeUsage(AttributeTargets.Class,AllowMultiple =true)]
    public class TableAttribute:Attribute
    {
        public string TableName { get; set; }//表名

        public TableAttribute()
        {

        }

        public TableAttribute(string TableName)
        {
            this.TableName = TableName;
        }

    }

查找特性

一般不直接实例化特性,而是通过反射找到标记特性的地方。
我们新建一个工具类CustomeAttribute,在里面写一个静态方法GetTAbleNameAttribute,用来查找特性。

public class CustomeAttribute
    {
        
        // 查找特性TableAttribute,获得表名
        public static string GetTAbleNameAttribute<T>(T mode) where T:class
        {
            Type type = typeof(T);
            if (type.IsDefined(typeof(TableAttribute),true))//IsDefined:根据特性类型查找该特性是否定义(存在),第二个参数表示是否有子级特性继承该特性
            {
                var attribute = type.GetCustomAttributes(typeof(TableAttribute), true);//获取所有特性

                return ((TableAttribute)attribute[0]).TableName;//找到就返回该特性的表名属性
            }
            else
            {
                return type.Name;//没有找到就返回传进来的类名
            }
        }


    }

使用特性

我们创建一个Student类,直接在类上调用该特性并传入表名即可,因为刚刚创建的特性就是为了拿到表名

 [TableAttribute("NewTable")]//实际上就是调用类的构造方法
   public class Student
    {
        
        public int Id { get; set; }
        public string   Name { get; set; }
        public string Email { get; set; }
        public int Age { get; set; }
        public string PhoneNumber { get; set; }

    }

我们可以在program里实例化该类然后使用工具类的查找特性方法来获得表名
string tableName = CustomeAttribute.GetTAbleNameAttribute(new Student());//调用方法拿到表名;

常用特性

using System.ComponentModel.DataAnnotations;命名空间下有一些常用特性

[Key]//说明这个属性是主键
        public int Id { get; set; }

        [StringLength(maximumLength:50,MinimumLength =4)]//字符串长度
        public string   Name { get; set; }

        [EmailAddress]//识别邮箱格式
        public string Email { get; set; }

        [Required]//属性不能为空
        public int Age { get; set; }

        [Display(Name="电话号码")]//显示字段的别名
        public string PhoneNumber { get; set; }

手动编写常用特性的功能

我们可以尝试自己去编写using System.ComponentModel.DataAnnotations;命名空间下的特性的功能
我们直接去掉using System.ComponentModel.DataAnnotations;命名空间
然后写一个CommonValidateAttribute特性,让它作为基类:

public abstract class CommonValidateAttribute:Attribute
    {

        public abstract bool IsValidate(object dataValue);

    }

然后创建五个类,继承CommonValidateAttribute特性,然后前缀就写的和系统的特性名一样引用即可

/// <summary>
    /// 主键特性
    /// </summary>
    public class KeyAttribute: CommonValidateAttribute
    {

        public bool IsPrimaryKey { get; set; } = true;

        public override bool IsValidate(object dataValue)
        {
            return IsPrimaryKey;
        }


    }
	
	
	/// <summary>
    /// 字符串长度验证
    /// </summary>
    public class StringLengthAttribute : CommonValidateAttribute
    {
        /// <summary>
        /// 最大值
        /// </summary>
        public int MaximumLength { get; set; }

        /// <summary>
        /// 最小值
        /// </summary>
        public int MinimumLength { get; set; }
		
        public StringLengthAttribute(int max, int min)
        {
            this.MaximumLength = max;
            this.MinimumLength = min;
        }

        public override bool IsValidate(object dataValue)
        {
            return MinimumLength <=dataValue.ToString().Length && dataValue.ToString().Length <= MaximumLength ;
        }
    }
	
	
	
	/// <summary>
    /// 邮箱认证
    /// </summary>
    public class EmailAddressAttribute : CommonValidateAttribute
    {
        public override bool IsValidate(object dataValue)
        {
            Regex regex = new Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");

            return regex.IsMatch(dataValue.ToString());
        }
    }
	
	
	
	 /// <summary>
    /// 非空验证
    /// </summary>
    public class RequiredAttribute : CommonValidateAttribute
    {
        public override bool IsValidate(object dataValue)
        {
            //判断属性值是否为空
            return dataValue != null && dataValue.ToString().Length != 0;
        }
    }
	
	
	//由于DisplayAttribute特性比较特殊,我们这里让其直接继承Attribute
	class DisplayAttribute:Attribute
    {
        public string Name { get; set; }

        public DisplayAttribute(string name)
        {

        }
    }


然后我们写一个工具类,用来存调用他们的方法的工具

//通用查找方法
        public static bool Validate<T>(T model)
        {
            //获取所有属性和特性
            PropertyInfo[] propertyInfos = model.GetType().GetProperties();


            //遍历属性和读取特性
            foreach (var property in propertyInfos)
            {
                if (property.IsDefined(typeof(CommonValidateAttribute),true))//判断该属性上面是否有特性,目的查找特性
                {
                    var attributes = property.GetCustomAttributes(typeof(CommonValidateAttribute),true);//获取该属性上面的所有特性(可能不止用了一个特性)

                    foreach (var item in attributes)
                    {
                        CommonValidateAttribute attribute = item as CommonValidateAttribute;//转换成对应类型

                        if (!attribute.IsValidate(property.GetValue(model)))
                        {
                            return false;
                        }
                       
                    }


                }
            }
            return true;

        }

我们在program写两个测试实例


Student student1 = new Student()
            {
                Id = 1,
                Name = "张三55",
                Age=13,
                Email="1160706425@qq.com"
            };

            Student student2 = new Student()
            {
                Id = 1,
                Name = "张",
                Email = "1234567890@qm"
            };


            bool result1 = CustomeAttribute.Validate(student1);//true
            bool result2 = CustomeAttribute.Validate(student2);//false

上面有两个特性验证还不会写

posted @   青仙  阅读(103)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示