zoukankan      html  css  js  c++  java
  • C# 自定义特性Attribute

    一、特性Attribute和注释有什么区别

    特性Attribute

      A:就是一个类,直接继承/间接继承Attribute

      B:特性可以在后期反射中处理,特性本身是没有什么*用的

      C:特性会影响编译和运行时功能

    注释

      A:就是对代码的解释和说明,其目的是让人们能够更加轻松地了解代码。注释是编写程序时,写程序的人给一个语句、程序段、函数等的解释或提示,能提高程序代码的可读性

      B:注释不能后期处理

    二、自定义Attribute特性的使用

    自定义Attribute特性的语法

    其实特性就是一个类,直接继承或者间接的继承Atrribute的就是一个特性

    首先声明特性,以下面的代码举个例子

    复制代码
    //直接继承Attribute
    public class CustomAttribute : Attribute
    {
        public string Name { get; set; }
    
        public CustomAttribute()
        {
            Console.WriteLine($"{this.GetType().Name} 无参构造函数");
        }
    
        public CustomAttribute(string name)
        {
            Console.WriteLine($"{this.GetType().Name} string 参数构造函数");
            Name = name;
        }
    }
    
    //间接继承Attribute
    public class CustomAttributeChild : CustomAttribute
    {
        public CustomAttributeChild()
        {
            Console.WriteLine($"{this.GetType().Name} 无参构造函数");
        }
    
        public CustomAttributeChild(string name) : base(name)
        {
            Console.WriteLine($"{this.GetType().Name} string 参数构造函数");
        }
    }
    复制代码

    特性的使用

    首先我们准备一个自定义特性DisplayName

    自定义特性

    复制代码
    /// <summary>
    /// 是给属性和字段 提供一个额外信息
    /// AllowMultiple特性影响编译器,AttributeTargets修饰的对象 AllowMultiple:能否重复修饰 Inherited:是否可继承
    /// 可以指定属性和字段
    /// </summary>
    namespace Ramon.Common.CustomAttribute
    {
        [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
        public sealed class DisplayNameAttribute : Attribute
        {
            public string Name { get; }
            public DisplayNameAttribute(string sValue)
            {
                Name = sValue;
            }
        }
    }
    复制代码

    在CompanyModel的属性上使用DisplayName的特性

    BaseModel

    namespace Ramon.Common.Framework
    {
        public class BaseModel
        {
            public int Id { get; set; }
        }
    }

    CompanyModel

    namespace Ramon.Model.Model
    {
        public class CompanyModel : BaseModel
        {
            [DisplayName("公司名称")]
            public string Name { get; set; }
    
            [DisplayName("创建日期")]
            public DateTime CreateTime { get; set; }
    
            [DisplayName("创建人Id")]
            public int CreatorId { get; set; }
    
            [DisplayName("最后修改人Id")]
            public int? LastModifierId { get; set; }
    
            [DisplayName("最后修改时间")]
            public DateTime? LastModifyTime { get; set; }
        }
    }

    我们标识了这些特性到底要怎么使用呢?

    文章的开始就已经说了特性可以在后期反射中处理,特性本身是没有什么*用的

    那么我们通过反射如何去使用特性

    接下来以上面给出的代码去实现,定义了一个扩展方法

    用到了反射和泛型等知识,如果有小伙伴不懂可参考以下文章
    反射:https://www.cnblogs.com/Ramon-Zeng/p/10189097.html
    泛型:https://www.cnblogs.com/Ramon-Zeng/p/10172818.html

    复制代码
     public static class BaseModelExtenstion
        {
            public static void ConsoleEntity<TEntity>(this TEntity tEntity) where TEntity : BaseModel
            {
                Type type = tEntity.GetType();
                PropertyInfo[] propInfos =  type.GetProperties();
                foreach (var prop in propInfos)
                {
                    string parameterName = prop.Name;
                    if (prop.IsDefined(typeof(DisplayNameAttribute), false))
                    {
                        DisplayNameAttribute attribute = (DisplayNameAttribute)prop.GetCustomAttribute(typeof(DisplayNameAttribute), false);
                        parameterName = attribute.Name.IsNullOrWhiteSpace() ? prop.Name : attribute.Name;
                    }
                    Console.WriteLine($"{parameterName}:{prop.GetValue(tEntity)}");
                }
            }
        }
    复制代码

    代码调用

    复制代码
    class Program
    {
        static void Main(string[] args)
        {
            CompanyModel companyModel = new CompanyModel()
            {
                Id = 1,
                Name = "Ramon----集团",
                CreateTime = DateTime.Now,
                CreatorId = 1,
            };
    
            companyModel.ConsoleEntity();
    
        }
    }
    复制代码

    结果

    二:特性的运用范围

    特性运用范围极其广,框架中我们看到上面的总结就晓得了,下面的我总结了以下几个地方也可以使用特性

    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;
            }
        }

    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; }
            
        }

    3:写下面的方法,使特性生效

    public class DataValidate
    {
            public static bool Validate<T>(T t)
            {
                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;
            }
        }

    4:应用判断时如下:

    Student student = new Student();
    student.Id = 123;
    student.Name = "MrSorry";
    student.QQ = 123456;
    var result = DataValidate.Validate(student);

    这样就完成了数据校验,特性校验的特点,总结得到了如下三点:

    1:可以校验多个属性
    2:可以支持多重校验
    3:支持规则的随意扩展

    运用了这个特性校验后,就不用再每个地方再分别写校验的逻辑,简单易用!

  • 相关阅读:
    006-STM32+BC26基本控制篇-基础应用-域名申请SSL证书
    005-STM32+BC26基本控制篇-基础应用-域名备案
    004-STM32+BC26基本控制篇-基础应用-购买域名,配置域名解析
    003-STM32+BC26基本控制篇-基础应用-安装Web服务器软件Nginx(.Windows系统)
    002-STM32+BC26基本控制篇-基础应用-测试APP扫码绑定BC26模组并实现APP和开发板之间通过MQTT进行远程通信控制
    Spark实战(六)spark SQL + hive(Python版)
    Spark实战(五)spark streaming + flume(Python版)
    Spark实战(二)Spark常用算子
    Spark面试常见问题(一)--RDD基础
    Spark实战(三)本地连接远程Spark(Python环境)
  • 原文地址:https://www.cnblogs.com/IT-Ramon/p/12061034.html
Copyright © 2011-2022 走看看