c#中的特性Attribute
⼀:特性是什么?特性怎么创建怎么使⽤?
这⼀章节,我想谈谈c#的特性⽅⾯的知识,特性⼤家在⼯作开发中都很熟悉,⽐如我们经常见到的
1:key Display --EF
2:Import
3:HttpGet HttpPost HttpDelete --MVC/WebApi
4:Serializable,Obsolete --系统单独功能
5:AutoMapFrom
6:WebMethod --WebService
7:Injection InjectionConstractor InjectMethod --IOC的特性
这些特性我们运⽤时感觉很简单,只需要简简单单的在类或者属性或者⽅法上⾯加 [特性的名字] 有时候
就能实现我们想要的效果,那今天我们就来揭开特性的⾯纱,看看特性到底是什么以及是怎么实现⼀些功能的?如想知道,请继续往下看!
通过使⽤反编译⼯具看IL中间语⾔发现,特性就是⼀个类,直接继承/间接继承Attribute⽗类,约定俗称使⽤Attribute结尾,标记的时候可以省略掉,可以使⽤[]包裹标记到元素,其实就调⽤的⽆参构造函数,特性起到标记的作⽤,从⽽影响编译器[Obsolete] 或者影响程序的运⾏([Serializable])等,下⾯我们创建⼀个特性如下:
///<summary>
///是给枚举⽤提供⼀个额外信息
/// AllowMultiple特性影响编译器,AttributeTargets修饰的对象 AllowMultiple:能否重复修饰 Inherited:是否可继承
///可以指定属性和字段
///</summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,AllowMultiple =true,Inherited =true)]
public class RemarkAttribute : Attribute
{
public RemarkAttribute()
{
}
public RemarkAttribute(string remark)
{
this.Remark = remark;
}
public string Description; //字段
public string Remark { get; private set; }
}
然后特性类上⾯的AttributeUsage也是⼀个特性,具体的⽤处见上⾯的注释解释,特性创建好了,我们可以创建⼀个实体,然后再实体的字段上⾯使⽤这个特性,具体如下:
[Remark("⽤户状态")]
public enum UserState
{
///<summary>
///正常
///</summary>
[Remark("正常")]
Normal = 0,
///<summary>
///冻结
///</summary>
[Remark("冻结")]
Frozen = 1,
///<summary>
///删除
///</summary>
[Remark("删除")]
Deleted = 2
}
因为AttributeTargets.Enum标识这个特性可以放在枚举上⾯,那我们上⾯那种代码也是完全被允许的,
此外,AttributeTargets如果不写,则默认是全部都可以使⽤的!特性创建和特性标识已经准备好了,然⽽怎么使特性⽣效呢?这个还是需要我们写代码来实现的
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();
}
}
}
使特性的⽣效的代码已经写好了,然后我们如果想要获得⼀个枚举的中⽂名字可以通过下⾯调⽤
UserState userState = UserState.Normal;
Console.WriteLine(userState.GetRemark());
这样我们就可以随⼼所欲的获取到这个枚举的中⽂备注了,没有使⽤特性之前,我们想要获取到枚举的中⽂备注,⼀般会只能写死判断,如下:
UserState userState = UserState.Normal;
if (userState == UserState.Normal)
{
Console.WriteLine("正常状态");
}
else if (userState == UserState.Frozen)
{
Console.WriteLine("冻结状态");
}
else
{
Console.WriteLine("删除状态");
}
然后⼀旦要修改状态名字,则代码也随着修改,这就会导致维护⽐较困难,如果使⽤了特性,则会⽤到的地⽅不需要太关注这些⽂字,只需要调⽤,然后修改的时候,只需要修改枚举上⾯的⽂字即可,极其容易维护!
⼆:特性的运⽤范围
特性运⽤范围极其⼴,框架中我们看到上⾯的总结就晓得了,下⾯的我总结了以下⼏个地⽅也可以使
⽤特性
1:数据展⽰不想展⽰属性名字,⽽是⽤中⽂描述
2:想指定哪个是主键,哪个是⾃增
3:别名数据库⾥⾯叫A 程序是B,怎么映射等
然后特性还可以校验⼀些数据字段等,下⾯我写个例⼦,以便更加容易理解:
1:先创建数据校验的特性
public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object oValue);
}
public class LongValidateAttribute : AbstractValidateAttribute
{
private long _lMin = 0;
private long _lMax = 0;
public LongValidateAttribute(long lMin, long lMax)
{
this._lMin = lMin;
this._lMax = lMax;
}
public override bool Validate(object oValue)
{
return this._lMin < (long)oValue && (long)oValue < this._lMax;
}
}
public class RequirdValidateAttribute : AbstractValidateAttribute
{
public override bool Validate(object oValue)
{
return oValue != null;
}
}
View Code
2:再⼀个实体类上⾯的字段增加特性
public class Student
{
[RequirdValidate]
public int Id { get; set; }
[LongValidate(5,10)]//还有各种检查
public string Name { get; set; }
[LongValidate(20, 50)]
public string Accont { get; set; }
///<summary>
/// 10001~999999999999
///</summary>
[LongValidate(10001, 999999999999)]
public long QQ { get; set; }
}
View Code
3:写下⾯的⽅法,使特性⽣效
public class DataValidate
{
public static bool Validate<T>(T t)
writeline特点{
Type type = t.GetType();
//IsDefined 是判断,不会调⽤构造函数
/
/if (type.IsDefined(typeof(AbstractValidateAttribute), true))
//{
////调⽤构造函数
// var oAttributeArray = type.GetCustomAttributes(typeof(AbstractValidateAttribute), true); // foreach (var item in oAttributeArray)
// {
// }
//}
//foreach (var method in type.GetMethods())
//{
// if (method.IsDefined(typeof(AbstractValidateAttribute), true))
// {
// object item = method.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0]; // AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
////if (!attribute.Validate(method.GetValue(t)))
////{
//// result = false;
//// break;
////}
// }
//}
bool result = true;
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
{
object item = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0];
AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
if (!attribute.Validate(prop.GetValue(t)))
{
result = false;
break;
}
}
}
return result;
}
}
View Code
4:应⽤判断时如下:
Student student = new Student();
student.Id = 123;
student.Name = "MrSorry";
student.QQ = 123456;
var result = DataValidate.Validate(student);
View Code
这样就完成了数据校验,特性校验的特点,总结得到了如下三点:
1:可以校验多个属性
2:可以⽀持多重校验
3:⽀持规则的随意扩展
运⽤了这个特性校验后,就不⽤再每个地⽅再分别写校验的逻辑,简单易⽤!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论