.Net 特性分析与妙用
一.特性是什么
1、想象很多小伙伴们都看过在一个类上方、或者在控制器见过类似的东东,加上之后就可以标识这个类或者方法就具备了某些特点 ,那我们就进入它的内心一探究竟吧。
2.我们进入某个特性之后,可以发现它又单独继承于Attribute 它的意思就是属性、特质的意思。那它到底能干嘛呢?能让我们写代码飞起吗??
二.走进特性
1.我们也写一个自己的特性,说干就来吧来。带着问题一步一步是魔鬼的步伐,兄弟们要我们干就完了,噢力给!!!
2.首先我们创建一个类(特性就是一个很单纯的类,我们一般以Attribute结尾命名),像这样我们的特性类就做好了,接下来怎么做呢?
3.创建完之后当然是使用它,它可以使用在类、方法、属性、枚举、参数、返回值上,使用的时候可以默认的省略Attribute,当我们使用[User]的时候就默认使用了[User()]就是在调用特性类的默认构造函数,特性必须存在一个或者多个构造方法,我们使用的时候就相当于执行特性的构造函数。好了知道怎么使用特性了,但是特性有什么卵用我还是不懂的样子!!!
4.上面我们已经知道了特性的创建和添加,但是还没有体现出有什么好处,在刚才我们创建了一个特性但是我们没有写任何代码,下面我们在创建一个新的特性进行使用。
我们假装一个场景我们需要判断用户支付订单的支付状态,我们会写一个枚举1待支付、2支付成功、3支付失败。
上面应该会是我们经常写的代码了吧,虽然说现在只有几个类型,但是类型多起来之后这里的判断就显得很冗余,又长又臭了。这里就不拐弯抹角我们可以使用特性去实现简单化。
/// <summary>
/// 获取类型名称的特性
/// </summary>
public class RemarkAttribute : Attribute
{
/// <summary>
/// 接受备注字段
/// </summary>
public string remarks { get; set; } /// <summary>
/// 构造函数
/// </summary>
public RemarkAttribute(string _remarks)
{
remarks = _remarks;
} /// <summary>
/// 返回备注字段
/// </summary>
/// <returns></returns>
public string GetRemarks()
{
return this.remarks;
}
}
上面我们创建了一个返回备注字段的特性,注意特性就是一个类,当然就拥有类所有东西,我们定义一个有参构造函数就收传过来的备注存在remarks属性中,然后通过GetRemarks()方法返回备注信息,然后我们怎么使用呢?我们在刚才的枚举中加入我们的特性,上面我们说过特性可以添加在枚举上
/// <summary>
/// 定义枚举
/// </summary>
public enum TypeEnum
{
/// <summary>
/// 待支付
/// </summary>
[Remark("待支付")]
ToPay = , /// <summary>
/// 支付成功
/// </summary>
[Remark("支付成功")]
PaymentSuccess = , /// <summary>
/// 支付失败
/// </summary>
[Remark("支付失败")]
PaymentFailure =
}
好了我们现在准备工作都做好了,特性我们也写了,使用特性的地方我们也加上了,但是我们要怎么获取特性的信息呢?一脸懵逼了,别急兄弟们慢慢来。这里就要使用反射,反射的特点你们还记得吗?它可以获取某个类,获取类的特性、属性、字段等等,还可以获取属性的特性。(反射篇)
/// <summary>
/// 编写一个枚举的拓展类
/// </summary>
public static class EnumExpand
{
/// <summary>
/// 获取枚举字段的返回备注
/// </summary>
/// <param name="enum"></param>
/// <returns></returns>
public static string GetTypeName(this Enum value)
{
//首先我们获取type类型
Type type = value.GetType();
//这里直接存起来方便返回
string strValue = value.ToString();
//然后我们是获取字段上面的特性,所以这里是一个
FieldInfo field = type.GetField(strValue);
///IsDefined判断类型是不是有这个类型。
///第二个属性:如果是真会根据继承链找是不是有这个类型
if (field.IsDefined(typeof(RemarkAttribute), true))
{
//GetCustomAttribute获取类型的特性.(这个的时候会去获取之前[User("111")]的类,相当于new,这个就是构造函数)
//第一个参数是类型
//第二个:如果是真会看自己的祖先有没有这个类型
RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
return attribute.GetRemarks();
}
else
{
return strValue;
}
}
}
上面是我们写的一个枚举的拓展方法,方便我们的使用。因为我们是在枚举的字段使用特性,这里获取调用方法的类,进行反射获取里面的成员(这里我们是在字段上面使用特性,所以获取枚举在获取里面的字段。)这样是不是比我们以前这么多判断更加方便简洁呢?
class Program
{
static void Main(string[] args)
{
TypeEnum typeEnum = TypeEnum.PaymentFailure;
Console.WriteLine(typeEnum.GetTypeName());
}
}
5.特性的限制
/// <summary>
/// AttributeUsage是特性的约束。
/// 第一个是限制这个特性可以作用在什么上面,
/// 第二个是显示这个特性可以不可以重复添加到一个上面
/// 第三个参数是限制特性可以不可以被继承到,把特性遗传到继承者上面
/// </summary>
[AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =true)]
特性也可以限制使用范围,AttributeTargets 限制使用的对象上面, AllowMultiple是否可以在同一个对象上面使用多次,默认是false,Inherited表示该特性是否可以被继承,默认情况下Inherited为true。
三、特性进阶
1.看到这里我相信我们的小伙伴已经知道了什么是特性以及编写属于自己的特性啦。为了巩固大家的记忆我们在来一个大家经常遇到的场景
情景剧场开始:我们经常需要判断用户输入的数据是不是正确的,经常需要些大量的判断,代码又长又重复(说到这里使用过EF的小伙伴肯定知道,可以在模型里面做限制哈哈)我们做两个场景需要判断某个字段的长度,以及大小.
/// <summary>
/// 继承抽象类,显示抽象类里面的方法
/// </summary>
public class ScopeAttribute : VerifyBaseAtttribute
{
/// <summary>
/// 最小值
/// </summary>
private int Min { get; set; } = ; /// <summary>
/// 最大值
/// </summary>
private int Max { get; set; } = ; /// <summary>
/// 限制长度
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public ScopeAttribute( int max = )
{
this.Max = max;
} /// <summary>
/// 限制长度
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public ScopeAttribute(int min = , int max = )
{
this.Min = min;
this.Max = max;
} /// <summary>
/// 判断长度范围修饰
/// </summary>
/// <returns></returns>
public override bool Verify(object value)
{
if (value == null)
{
return false;
}
Type type = value.GetType();
string str = value.ToString();
if (string.IsNullOrWhiteSpace(str))
{
return false;
}
int Length = str.Length;
if (Min > && Max > )
{
return Length > Min && Length < Max ? true : false;
}
else if (Min > )
{
return Length > Min ? true : false;
}
else if (Max > )
{
return Length < Max ? true : false;
}
return false;
}
}
/// <summary>
/// 判断qq号
/// </summary>
public class QQAttribute : VerifyBaseAtttribute
{
/// <summary>
/// 最小值
/// </summary>
private int Min { get; set; } /// <summary>
/// 最大值
/// </summary>
private int Max { get; set; } /// <summary>
/// 判断区间数
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public QQAttribute(int min = , int max = )
{
this.Min = min;
this.Max = max;
} /// <summary>
/// 判断长度范围修饰
/// </summary>
/// <returns></returns>
public override bool Verify(object value)
{
if (value == null)
{
return false;
}
Type type = value.GetType();
if (type == typeof(int))
{
int valueInt = Convert.ToInt32(value);
if (valueInt == ) return false;
return valueInt > Min && valueInt < Max ? true : false;
}
return false;
}
}
/// <summary>
/// 验证父类特性
/// 主要就是给验证特性提供一个统一的入口
/// 实现方式:接口形式、抽象类形式进行重写(这里我使用抽象类实现)
/// </summary>
public abstract class VerifyBaseAtttribute : Attribute
{
/// <summary>
/// 统一验证的入口
/// </summary>
/// <returns></returns>
public abstract bool Verify(object value);
}
看了上面三段代码你就会很疑惑为什么,你写了一个抽象的特性?????满脸问号等下就告诉你。
public static class EntityExpands
{
/// <summary>
/// 验证方法
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="model">实体</param>
/// <returns></returns>
public static bool Verify<T>(this T model) where T : class, new()//限制这个拓展方法只能使用在可以实例化的类上
{
//获取实体模型
Type type = model.GetType();
//获取实体的所有属性
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
//遍历属性,判断属性是否存在VerifyBaseAtttribute特性,true会去查看继承链是否存在
//这个之所以使用Base特性就是抽象出验证特性共同的东西,所有验证都可以调用这个方法生效
if (propertyInfo.IsDefined(typeof(VerifyBaseAtttribute), true))
{
//然后获取属性上面的特性(注意一个属性上面可能会出现多个验证特性,所以这里我们需要获取一个数组)
object[] atttribute = propertyInfo.GetCustomAttributes(typeof(VerifyBaseAtttribute), true);
//进行遍历
foreach (VerifyBaseAtttribute item in atttribute)
{
//调用验证方法,传入属性的值
if (!item.Verify(propertyInfo.GetValue(model)))
{
//失败返回
return false;
}
}
}
}
return true;
}
}
四、个人总结
1、首先特性相当于一个补充类(就是一个类),他可以在不该变使用者的前提下,给使用者添加字段或者放法行为 好比我以前用过的拦截器 就是继承了特性然后进行了拓展的,AOP思想.,我们将一些不相干的逻辑可以放到特性里面,简化我们主干代码的逻辑和代码量。
.Net 特性分析与妙用的更多相关文章
- MySQL · 特性分析 · 优化器 MRR & BKA【转】
MySQL · 特性分析 · 优化器 MRR & BKA 上一篇文章咱们对 ICP 进行了一次全面的分析,本篇文章小编继续为大家分析优化器的另外两个选项: MRR & batched_ ...
- MySQL · 特性分析 · MDL 实现分析
http://mysql.taobao.org/monthly/2015/11/04/ 前言 在MySQL中,DDL是不属于事务范畴的,如果事务和DDL并行执行,操作相关联的表的话,会出现各种意想不到 ...
- hive 桶相关特性分析
1. hive 桶相关概念 桶(bucket)是指将表或分区中指定列的值为key进行hash,hash到指定的桶中,这样可以支持高效采样工作. 抽样( sampling )可以在全体数 ...
- node.js http接口调试时请求串行特性分析
缘起: 产品业务上有个类数据库服务的请求时间比较长(类似mysql的sql查询),为了优化减少并发时的请求数,做了一个并发时共用请求的优化. 通过单元测试后,想通过手动模拟看下效果,发现优化一直不能生 ...
- Nor Flash芯片特性分析
Nor Flash是Intel在1988年推出的非易失闪存芯片,可随机读取,擦写时间长,可以擦写1~100W次,支持XIP(eXecute In Place). 本文以JS28F512M29EWH为例 ...
- BFC的形成条件和特性分析
初学CSS时,我们学到很多有意思的CSS规则,比如外边距塌陷,还有浮动元素的一些特性等,其实这些规则背后都是BFC这个东西在控制,下面我们来看下BFC到底是什么. 什么是BFC BFC(Block f ...
- 针对无线信道衰落特性分析3G,4G,5G的关键技术异同点
1 无线信道特性对3G系统的影响 2
- Android 4.4 新特性分析-15项大改进!
Google发布了Android 4.4 KitKat,并其同时面世的还有新旗舰Nexus 5.Android 4.4 KitKat有怎样的改进.是否值得升级呢,下面就为大家呈现Android 4.4 ...
- 了解与建设有中国特色的Android M&N(Android6.0和7.0新特性分析)
http://geek.csdn.NET/news/detail/110434 Android N已经发布有段时间,甚至马上都要发布android 7.1,相信不少玩机爱好者已经刷入最新的Androi ...
随机推荐
- netstat - 系统信息
netstat - 系统信息 注意:如果是勘验或者验证漏洞,需要验证netstat程序的完整性(netstat程序是否被修改过). # 老版本的CentOS中会自带这个软件包,新版的7有的时候需要单独 ...
- day31-hmac模块检测客户端是否合法
#如果客户端知道服务端的ip地址和端口,就可以连接服务端,信息不安全. #使用os.urandam随机生成32位bytes,然后hmac加密之后再发送给客户端. #server: import soc ...
- 在Linux中#!/usr/bin/python之后把后面的代码当成程序来执行。 但是在windows中用IDLE编程的话#后面的都是注释,之后的代码都被当成文本了。 该怎么样才能解决这个问题呢?
本文转自:http://bbs.csdn.net/topics/392027744?locationNum=6&fps=1 这种问题是大神不屑于解答,小白又完全不懂的问题... 同遇到这个问题 ...
- 敏捷开发方法(一) Scrum
Scrum团队:由产品负责人.开发团队和Scrum Master组成. 是跨职能的自组织团队 自组织团队自己选择如何最好地完成工作,而不是由团队外的人指导 跨职能团队拥有完成工作所需要的全部技能,不需 ...
- 吴裕雄--天生自然 R语言开发学习:时间序列(续二)
#-----------------------------------------# # R in Action (2nd ed): Chapter 15 # # Time series # # r ...
- EL表达式详细教程
EL 全名为Expression Language EL 语法很简单,它最大的特点就是使用上很方便.接下来介绍EL主要的语法结构: ${sessionScope.user.sex} 所有EL都是以${ ...
- AFNetworking基本模块
AFNetworking主要分为5个模块 通信模块(AFURLSessionManager, AFHTTPSessionManager) 网络状态监听 安全模块 通信序列化/反序列化模块 UIKit相 ...
- 查漏补缺:Vector中去重
对于STL去重,可以使用<algorithm>中提供的unique()函数. unique()函数用于去除相邻元素中的重复元素(所以去重前需要对vector进行排序),只留下一个.返回去重 ...
- Android API Levels
Android API Levels(转) 在本文中 API的级别是什么? 在Android中使用API级别 开发者需要考虑的内容 应用程序的向前兼容性 应用程序的向后兼容性 平台版本和API级别的选 ...
- 用新架构适配MI3中遇到的各种坑
用新架构适配MI3中遇到的各种坑 首先不得不说hendy架构的强大之处, mi3也直接开机但是遇到各种坑,不能怪架构不够强大,只有说miui定制化太高.下面详细说一下mi3适配中的各种坑.有些坑会附带 ...