.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 = 1,

        /// <summary>
        /// 支付成功
        /// </summary>
        [Remark("支付成功")]
        PaymentSuccess = 2,

        /// <summary>
        /// 支付失败
        /// </summary>
        [Remark("支付失败")]
        PaymentFailure = 3
    }

  好了我们现在准备工作都做好了,特性我们也写了,使用特性的地方我们也加上了,但是我们要怎么获取特性的信息呢?一脸懵逼了,别急兄弟们慢慢来。这里就要使用反射,反射的特点你们还记得吗?它可以获取某个类,获取类的特性、属性、字段等等,还可以获取属性的特性。(反射篇

 /// <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; } = 0;

        /// <summary>
        /// 最大值
        /// </summary>
        private int Max { get; set; } = 0;

        /// <summary>
        /// 限制长度
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        public ScopeAttribute( int max = 0)
        {
            this.Max = max;
        }

        /// <summary>
        /// 限制长度
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        public ScopeAttribute(int min = 0, int max = 0)
        {
            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 > 0 && Max > 0)
            {
                return Length > Min && Length < Max ? true : false;
            }
            else if (Min > 0)
            {
                return Length > Min ? true : false;
            }
            else if (Max > 0)
            {
                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 = 0, int max = 0)
        {
            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 == 0) 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思想.,我们将一些不相干的逻辑可以放到特性里面,简化我们主干代码的逻辑和代码量。

原文地址:https://www.cnblogs.com/chenxi001/p/12431710.html

时间: 2024-08-30 12:07:43

.Net 特性分析与妙用的相关文章

智能路由器安全特性分析

智能路由器安全特性分析 腾讯安全中心 · 2015/07/21 14:09 博文作者:zhuliang 0x00 前言 随着互联网的发展,越来越多公司推出了智能路由器,这些智能路由器给用户带来了众多便利的功能,同时也采用了一些传统路由器不具备的安全特性,本文在简要分析下这些安全特性,供相关技术人员参考. 0x01 概述 传统路由器有意或无意地使用了种种不安全的特性,如预留后门,这些后门原本是为了现场调试方便,但是也开放了黑客进入的通道.又比如某些路由器WPS(Wi-Fi Protected Se

BFC的形成条件和特性分析

初学CSS时,我们学到很多有意思的CSS规则,比如外边距塌陷,还有浮动元素的一些特性等,其实这些规则背后都是BFC这个东西在控制,下面我们来看下BFC到底是什么. 什么是BFC BFC(Block formatting contexts),翻译过来就是块级格式化上下文,指的是一种上下文环境,我们暂且不管它为什么叫这么晦涩冗长的名字,先看看哪些情况能形成BFC,然后看看它有哪些特性,这样我们也就知道它是什么了.就像我们学习js的对象一样,了解一个对象的原型,以及它的属性方法,我们也就知道它是什么了

JAVA的三大基本特性分析

众所周知的一件事情就是,JAVA作为一个面向对象的编程语言,是有三大特性的.这三个特性分别是:封装,继承和多态. 在面试的过程中遇到这个问题的概率是比较大的,特别是一些刚出校门的大学生在求职时几乎全部都会遇到这个问题.考官其实也知道这个问题是非常基本的,主要也就是拿这一道题先争取一点时间--他看看简历.就我们公司的实际情况而言,很多人来面试,我们的同事去面试的时候都是被赶鸭子上架,并不乐意做这项工作.既然面试官问了,回答也不能敷衍,虽然这个问题很小白,但是想要说得出彩确实是很难的,因为一般最简单

针对无线信道衰落特性分析3G,4G,5G的关键技术异同点

1 无线信道特性对3G系统的影响 2

关于GFW的功能原理和特性分析[转]

lz的gmail和dropbox被墙不能用之后迁移到outlook和onedrive花了整整一下午时间.最关键的是从6月30日开始onedrive突然也被墙了(同时也包括line等).简直吐血.(此处默默看了一眼我的印象笔记 .用了三年会员四百多篇笔记两千多张照片假如被墙的话....)出于对于白帽事业的热爱.稍微研究了一下GFW.正义网友与GFW的斗争.一刻也没有停止过.方校长微博拜年换来几万个"滚".就能说明这个问题.甚至GFW除了阻止我们自由地访问互联网之外.还有发动中间人攻击.D

IOS:Camera的特性分析与使用

Camera是IOS中很重要的一个信息获取途径. 以下我们主要从硬件特性以及软件特性两个方面来看看Canera的使用,先来看看软件上我们使用Camera都能干点什么. 先来看看以下一张图: 相机软件部分主要介绍两个部分: <1> UIImagePickerController <2> AVCapture AVCapture的结构和使用在前面的博客中已经介绍了,这里先来看看UIImagePickerController的相关特点. 我们使用UIImagePickerControlle

Application 效能分析有妙招 — 使用 perf 走天下(转载)

转载:http://tech.mozilla.com.tw/posts/1803/application-%E6%95%88%E8%83%BD%E5%88%86%E6%9E%90-%E4%BD%BF%E7%94%A8-perf 在手機上面,Application 的實作往往會影響到效能好壞以及是否夠省電,其中 Application 的 CPU 使用量會是一個非常關鍵的因素. 以下就拿使用 Firefox OS 的手機來做舉例說明,首先透過下面的 top 指令,可以看到整體 System 以及

JPG和PNG特性分析及适用范围

JPG的特性   ----有损压缩 1.支持摄影图像或写实图像的高级压缩,并且可利用压缩比例控制图像文件大小. 2.有损压缩会使图像数据质量下降,并且在编辑和重新保存JPG格式图像时,这种下降损失会累积. 3.JPG不适用于所含颜色很少.具有大块颜色相近的区域或亮度差异十分明显的较简单的图片. PNG的特性   ----无所压缩 1.能在保证最不失真的情况下尽可能压缩图像文件的大小. 2.PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且还可存

Swoole定时器Timer特性分析与使用

Swoole是一个使用c开发的php扩展,通过php就可以实现高性能web服务器,同时,还内置了定时器Timer.任务队列Task特性.这样,基于swoole,你可以在程序层面控制实现方式,减少对外部工具 - 独立的消息队列服务器.定时任务管理工具等的依赖性. swoole的强大之处就在与其进程模型的设计,既解决了异步问题,又解决了并行.用法如下: swoole_server_addtimer($serv, 10); 第二个参数是定时器的间隔时间,单位为秒.swoole定时器的最小颗粒是1秒.支