特性Attribute,和注释有什么区别
- 注释:是让人看的懂代码,不影响程序的运行,和编译器
- 特性:特性可以影响编译器,特性可以影响程序的运行,特性编译后生成的是一个metadata
[Obsolete(请不要用这个了,请使用什么来代替,true)] //过时了 可以用来标记已经不用了的方法,
[Serializable] //可以序列化和反序列化
声明和使用attribute,AttributeUsage
- 声明和使用
- 特性:特性是一个 直接/间接 继承attribute的类。约定俗成的用Attribute结尾,然后声明的时候可以省略
- 特性可以修饰类,字段,属性,方法,参数,返回值([return:名称]), 基本上所有的元素上都可以修饰
- 特性在声明得时候还可以直接给自己得属性或字段赋值
[Custom("这是一个学生",ID=1234)]
[Custom(Name="学生",Remark="备注")]
public class Student
{
[Custom]
public int ID { get; set; }
[Custom]
[RequirdValidate]//非空验证
public string Name { get; set; }
[Custom]//qq号长度验证
[LongValidate(10000,99999999999)]
public long QQ { get; set; }
[Custom]
public string QQ_password { get; set; }
[Custom]
public string Remark { get; set; }
[Custom]
public Student() { Console.WriteLine("这里是student类"); }
/// <summary>
/// 展示字段的值
/// </summary>
[Custom]
public void Show()
{
Console.WriteLine($"ID={ID},Name={Name},QQ={QQ},QQ密码={QQ_password},Remark={Remark}");
}
/// <summary>
/// 自我介绍
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[Custom]
[return:Custom]
public string SelfIntroduction(string name)
{
return $"你好,我是{name}";
}
}
- AttributeUsage
这个特性用来修饰特性,可以修来约束特性的范围,是否可以多重修饰,子类是否是特效
AttributeTargets 特性的目标、AllowMultiple 多重修饰,默认false、Inheriter 子类是否是特性,默认true、一般不会重复修饰,没又意义
[AttributeUsage(AttributeTargets.All,AllowMultiple=false,Inheriter=true)]
public class CustomAttribute : Attribute
{
public CustomAttribute()
{
}
public CustomAttribute(string name)
{
this.Name=name;
}
public int ID{get;set;}
public string Name{get;set;}
public string Remark{get;set;}
}
注意:特性在我们不使用的时候一点用都没有,就跟注释差不多,特性本身是毫无价值的
如何使用:特性编译后生成的是一个metadata,只有使用反射才有用
运行中获取Attribute:额外信息 额外操作
特性在声明后,本身是没有用的,对我们的程序是没有影响的
除非我们在使用的过程中主动去找它,主动找它的过程中是通过反射的方式,找的时候才会去实例化这些特性
Student student = new Student();
student.ID = 1;
student.Name = "小明";
student.QQ = 927281458;
student.QQ_password = "123";
student.Remark = "我是一个小学生!";
如何主动去调用特性
//主动
//使用反射去调用
Type type = student.GetType();
if (type.IsDefined(typeof(CustomAttribute), true))//检测有没有这个特性
{
object item = type.GetCustomAttributes(typeof(CustomAttribute), true)[0];
//foreach (var item in type.GetCustomAttributes(typeof(CustomAttribute), true))
{
CustomAttribute attribute = item as CustomAttribute;
attribute.Show();
}
}
foreach (var item in type.GetProperties())//属性
{
if (item.IsDefined(typeof(CustomAttribute), true))//检查该属性是否有这个特性
{
object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
}
foreach (var item in type.GetFields())//字段
{
if (item.IsDefined(typeof(CustomAttribute), true))//检查该字段是否有这个特性
{
object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
}
foreach (var item in type.GetConstructors())//构造函数
{
if (item.IsDefined(typeof(CustomAttribute), true))
{
object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
}
MethodInfo method = type.GetMethod("SelfIntroduction");//获取这个方法
if (method.IsDefined(typeof(CustomAttribute), true))
{
object item = method.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
foreach (var item in method.GetParameters())//这个SelfIntroduction方法的 所有参数
{
if (item.IsDefined(typeof(CustomAttribute), true))
{
object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
}
if (method.ReturnParameter.IsDefined(typeof(CustomAttribute), true))//返回参数是否有这个属性
{
object oAttribute = method.ReturnParameter.GetCustomAttributes(typeof(CustomAttribute), true)[0];
}
自定义特性
/// <summary>
/// 自定义特性
/// </summary>
[AttributeUsage(AttributeTargets.All)]//AttributeTargets.All 所有元素
public class CustomAttribute : Attribute
{
public CustomAttribute()
{
Console.WriteLine("这是一个无参数的构造函数");
}
public CustomAttribute(string name)
{
this.Name = name;
Console.WriteLine("这是一个有参数的构造函数");
}
public int ID { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
public void Show()
{
Console.WriteLine($"ID={ID},Name={Name},Remark={Remark}");
}
}
请看下面这个实列:
- 我们创建一个特性RemarkAttribute,继承Attribute,在创建一个UserState用户状态的枚举,和一个RemarkExtend的扩展类,提供一个扩展方法 GetRemark() 用于获取枚举的一个额外信息。
- 如何调用,如下
RemarkExtend.GetRemark(UserState.Deleted); //得到的是删除
或者 UserState.Deleted.GetRemark();//得到的是删除
/// <summary>
/// 是给枚举用 提供一个额外信息
/// </summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public class RemarkAttribute : Attribute
{
public RemarkAttribute(string remark)
{
this.Remark = remark;
}
public string Remark { get; private set; }
}
public static class RemarkExtend
{
/// <summary>
/// 扩展方法
/// </summary>
/// <param name="enumValue"></param>
/// <returns></returns>
public static string GetRemark(this Enum enumValue)
{
Type type = enumValue.GetType();
FieldInfo field = type.GetField(enumValue.ToString());
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute remarkAttribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute));
return remarkAttribute.Remark;
}
else
{
return enumValue.ToString();
}
}
}
[Remark("用户状态")]
public enum UserState
{
/// <summary>
/// 正常
/// </summary>
[Remark("正常")]
Normal = 0,
/// <summary>
/// 冻结
/// </summary>
[Remark("冻结")]
Frozen = 1,
/// <summary>
/// 删除
/// </summary>
[Remark("删除")]
Deleted = 2
}
在来看我们另外的一个实列:非空验证和长度验证
- 创建特性AbstractValidateAttribute用类验证数据的特性
- 创建一个LongValidateAttribute验证长度的特性继承AbstractValidateAttribute,并实现其中的方法
- 创建一个RequirdValidateAttribute验证非空的特性继承AbstractValidateAttribute,并实现其中的方法
- 创建一个DataValidate的扩展类并扩展一个Validate的扩展方法,返回一个bool类型的值,当属性字段不满足要求时,会返回一个false
/// <summary>
/// 验证数据特性
/// </summary>
public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object oValue);
}
/// <summary>
/// 验证长度特性
/// </summary>
public class LongValidateAttribute : AbstractValidateAttribute
{
private long _lMin = 0;
private long _lMax = 0;
public LongValidateAttribute(long lMin, long lMax)
{
this._lMin = lMin;
this._lMax = lMax;
}
/// <summary>
/// 输入得值是否在这个范围类
/// </summary>
/// <param name="oValue"></param>
/// <returns></returns>
public override bool Validate(object oValue)
{
return _lMin <= (long)oValue && (long)oValue >= _lMax;
}
}
/// <summary>
/// 验证是否非空特性
/// </summary>
public class RequirdValidateAttribute : AbstractValidateAttribute
{
public override bool Validate(object oValue)
{
return oValue != null;
}
}
public static class DataValidate
{
public static bool Validate<T>(T t)//验证数据是否正确
{
Type type = t.GetType();
bool result = true;
foreach (var prop in type.GetProperties())//取得该类得属性的信息
{
if (prop.IsDefined(typeof(AbstractValidateAttribute), true))//该属性是否存在AbstractValidateAttribute这条特性
{
object item = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0];//获取当前属性得AbstractValidateAttribute特性对象 返回得是应该object
AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
if (!attribute.Validate(prop.GetValue(t)))//prop.GetValue(t) 当前属性得值
{
result = false;
break;
}
}
}
return result;
}
}
总结:
特性:是一个类,可以用来标记元素,编译时生成到metadata里,平时不影响程序的运行除非主动用反射去查找,可以得到一些额外的信息/操作,然后提供了更丰富的扩展空间。
特性可以在不破坏类型封装的前提下,额外的增加功能