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
上面有两个特性验证还不会写
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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语句:使用策略模式优化代码结构