C# 特性(Attribute)
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。
特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
添加特性之后会在对应的位置添加特性中的代码,我们是看不到的,通过反编译查看IL中间语言可以查看。
特性是需要主动调用才会生效,像MVC,EF中的特性是因为官方写好了,我们直接用。
特性的使用:
1.Obsolete:用于声明方法过时
// 使用时提示方法过时警告
[Obsolete("该方法已经过时")]
// 使用时提示方法错误,直接报错
//[Obsolete("该方法已经过时,直接报错",true)]
public void ObsoleteDemo()
{
}
// 调用
Demo demo = new Demo();
demo.ObsoleteDemo();
// 或发现demo.ObsoleteDemo(); 绿色波浪线提示方法已过时
2.自定义特性在不同位置的使用:
// [Custom]等同于 [Custom()]:标识执行无参数的构造
// 但是一般同时写会出错,提示特性重复,解决方法:在对用的特性类里面添加: [AttributeUsage(AttributeTargets.All,AllowMultiple =true)] 即可
//[Custom]
// [Custom(123)]:表示有参数的构造函数
[Custom(123, Description = "类上的特性", Remark = "类上的特性")]
public class Student
{
// 无参数的构造函数
[Custom(Description = "属性上的特性", Remark = "属性上的特性")]
public int Id { get; set; }
public string Name { get; set; }
[Custom(Description = "方法上的特性", Remark = "方法上的特性")]
public void Study()
{
Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
}
[Custom(Description = "方法上的特性", Remark = "方法上的特性")]
[return: Custom(Description = "返回值上的特性", Remark = "返回值上的特性")]
public string Answer([Custom(Description = "方法上的参数的特性", Remark = "方法上的参数的特性")] string name)
{
return $"This is {name}";
}
}
// 关于上述Student实体类各种特性的调用方法:
public static void Show(Student student)
{
Console.WriteLine($"-------------------获取特性-------------------");
Type type = typeof(Student);
// 或者 student.GetType();
#region 类上面的特性
{
Console.WriteLine($"-------------------类上面的特性-------------------");
// 查找是否有指定的特性
if (type.IsDefined(typeof(CustomAttribute), true))
{
// 如果有,获取特性
// 这句话其实就是去执行 CustomAttribute 类的 构造函数 字段。。。
object aAttribute = type.GetCustomAttribute(typeof(CustomAttribute), true);
// 将找到的转化为 CustomAttribute 类型的attribute
CustomAttribute customAttribute = (CustomAttribute)aAttribute;
Console.WriteLine($"{customAttribute.Description}_{customAttribute.Remark}");
// 通过反射执行特性类中的方法
customAttribute.Show();
}
}
#endregion
#region 参数上的特性
{
Console.WriteLine($"-------------------参数上的特性-------------------");
// 获取指定名称的公共属性
PropertyInfo property = type.GetProperty("Id");
if (property.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = (CustomAttribute)property.GetCustomAttribute(typeof(CustomAttribute), true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}
}
#endregion
#region 方法上的特性
{
Console.WriteLine($"-------------------方法上的特性-------------------");
// 获取指定名称的方法
MethodInfo method = type.GetMethod("Answer");
if (method.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute), true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}
Console.WriteLine($"-------------------方法上传递的参数的特性-------------------");
// 获取指定方法或者构造函数的参数
ParameterInfo parameterInfo = method.GetParameters()[0];
if (parameterInfo.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute), true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}
Console.WriteLine($"-------------------方法上返回值的特性-------------------");
// 获取指定方法的返回值
ParameterInfo returnParameterInfo = method.ReturnParameter;
if (returnParameterInfo.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = (CustomAttribute)returnParameterInfo.GetCustomAttribute(typeof(CustomAttribute), true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}
}
#endregion
}
3.使用特性去获取美剧的备注信息
/// <summary>
/// 用户状态
/// </summary>
public enum UserState
{
/// <summary>
/// 正常
/// </summary>
[Remark("正常")]
Normal = 0,//左边是字段名称 右边是数据库值 哪里放描述? 注释
/// <summary>
/// 冻结
/// </summary>
[Remark("冻结")]
Frozen = 1,
/// <summary>
/// 删除
/// </summary>
//[Remark("删除")]
Deleted = 2
}
//枚举项加一个描述 实体类的属性也可以Display
//别名 映射
public class RemarkAttribute : Attribute
{
public RemarkAttribute(string remark)
{
this._Remark = remark;
}
private string _Remark = null;
public string GetRemark()
{
return this._Remark;
}
}
public static class RemarkExtension
{
public static string GetRemark(this Enum value)
{
Type type = value.GetType();
FieldInfo field = type.GetField(value.ToString());
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
return attribute.GetRemark();
}
else
{
return value.ToString();
}
}
}
4.使用特性做表单数据提交的验证:
public static class ValidateExtension
{
public static bool Validate(this object oObject)
{
Type type = oObject.GetType();
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
{
object[] attributeArray = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true);
foreach (AbstractValidateAttribute attribute in attributeArray)
{
if (!attribute.Validate(prop.GetValue(oObject)))
{
return false;//表示终止
}
}
}
//if (prop.IsDefined(typeof(LongAttribute), true))
//{
// LongAttribute attribute = (LongAttribute)prop.GetCustomAttribute(typeof(LongAttribute), true);
// if (!attribute.Validate(prop.GetValue(oObject)))
// {
// return false;
// }
//}
//if (prop.IsDefined(typeof(LengAttribute), true))
//{
// LengAttribute attribute = (LengAttribute)prop.GetCustomAttribute(typeof(LengAttribute), true);
// if (!attribute.Validate(prop.GetValue(oObject)))
// {
// return false;
// }
//}
}
return true;
}
}
public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object value);
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class LengAttribute : AbstractValidateAttribute
{
private int _Min = 0;
private int _Max = 0;
public LengAttribute(int min, int max)
{
this._Min = min;
this._Max = max;
}
public override bool Validate(object value)//" "
{
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
int length = value.ToString().Length;
if (length > this._Min && length < this._Max)
{
return true;
}
}
return false;
}
}
public class LongAttribute : AbstractValidateAttribute
{
private long _Min = 0;
private long _Max = 0;
public LongAttribute(long min, long max)
{
this._Min = min;
this._Max = max;
}
public override bool Validate(object value)//" "
{
//可以改成一句话
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
if (long.TryParse(value.ToString(), out long lResult))
{
if (lResult > this._Min && lResult < this._Max)
{
return true;
}
}
}
return false;
}
}