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:支持规则的随意扩展

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

原文地址:https://www.cnblogs.com/IT-Ramon/p/12061034.html

时间: 2024-10-14 00:57:51

C# 自定义特性Attribute的相关文章

Attribute(二)——自定义特性+Asp.net MVC中的filter详解

上篇博客是关于特性中有关预定义特性的一些基础,同时也是对Attribute这一概念的一个宏观上的认识,在上篇博客结尾介绍了有关为自定义特性服务的AttributeUsage,这篇博客主要是通过filter的使用间接的了解自定义特性的具体应用. 一.filter简介 在了解自定义特性前,先引入一个概念filter,它是MVC中自带的一种功能,在我们项目中通常会遇到在Action执行前或结束时,去执行日志记录或错误处理等功能,通常可使用AOP截取来实现,但是在MVC中提供了filter过滤,大大方便

自定义特性。配合枚举使用棒棒哒

1 /// <summary> 2 /// 自定义特性,比系统的display增加了一些参数 Created by ZhangQC 2015.08.19 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 5 AllowMultiple = false, Inherited = false)] 6 public sealed class CustomAttrib

.NET基础编程之特性 - Attribute

这一篇文章是给大家介绍的是:.NET基础编程之特性 - Attribute,对这一部分掌握不熟悉的同学,可以仔细的看一下! 一.特性简介 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用"反射"查询特性. 特性具有以下属性: (1)特性可向程序中添加元数据.元数据是有关在程序中定义的类型的信息.所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员.可以添加自定义特性,以

自定义特性用途---案例:操作权限

--------------------------------------------------LimitAttribute.cs   自定义特性 using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary> /// LimitAttribute 的摘要说明 /// </summary> //特性只作用与方法上 [AttributeUsage(

C#编程(七十一)---------- 自定义特性

自定义特性 在说自定义之前,有必要先介绍一些基本的概念. 元数据:就是C#中封装的一些类,无法修改,类成员的特性被称为元数据中的注释 1.什么是特性? (1)属性和特性的区别 属性:属性是面向对象思想里所说的封装在类里面的数据字段,Get,Set方法. 特性:就相当于类的元数据. 来看看官方解释? 特性是给指定的某一声明的一则附加的声明性信息. 允许类似关键字的描述声明.它对程序中的元素进行标注,如类型.字段.方法.属性等.从.net角度看,特性是一种 类,这些类继承于System.Attrib

.Net之自定义特性

刚接触C#的朋友常常容易把属性(Property)跟特性(Attribute)搞混,其实这是两种不同的东西 属性指的类中封装的数据字段:而特性是对类.字段.方法和属性等元素标注的声明性信息 如下代码(Id.Name为User的属性,[DbKey]为Id的特性) /// <summary> /// 用户信息 /// </summary> public class User { [DbKey] public string Id { get; set; } public string N

利用反射来实现获取成员的指定特性(Attribute)信息

在开发过程中,我们经常需要自定义一些特性,来辅助我们完成对对象或者枚举进行管理.我们需要知道如何获取对象使用的特性信息. 以下举个学习用的例子. 我们自定义一个特性类,这个特性设置在一个数据段内是否执行使用这个特性的方法,特性如下 [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public class ExcuceAttribute : Attribute { public

.Net:自定义特性(Custom Attributes)的创建与查看

有时候,我们会看到这样的东西放在类或者方法上面: [Obsolete("请更新方法")] 刚开始的时候,还自己给它起了个名字--小标签,比如,平常会说:你数据契约是不是没打标签啊!~嘿嘿~ 后来跟代码发现了更多的不认识的自定义标签.那么,这些标签是怎么定义和使用的呢? 定义Attribute 如下,定义了一个用于记录类变更的attribute,不允许继承,允许多次使用. [AttributeUsage(AttributeTargets.Class, Inherited = false,

.Net内置特性Attribute介绍

特性Attribute概述 特性(Attribute)是一种特殊的类型,可以加载到程序集或者程序集的类型上,这些类型包括模块.类.接口.结构.构造函数.方法.字段等,加载了特性的类型称之为特性的目标.这里为与属性(Property)区分,所以称之为特性(Attribute).特性是为程序集添加元数据的一种机制,通过它可以为编译器提供指示或者对数据进行说明.例如前段时间学习的Remoting技术(主要用于应用程序域之间的对象通信)中在应用程序域间的引用对象时该对象具有序列化(Serializabl