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

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

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

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

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

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

用到了反射和泛型等知识,如果有小伙伴不懂可参考以下文章
反射: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:先创建数据校验的特性

 View Code

2:再一个实体类上面的字段增加特性

 View Code

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

 View Code

4:应用判断时如下:

 View Code

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

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

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

参考文章:https://www.cnblogs.com/loverwangshan/p/10153832.html

posted @ 2018-12-20 17:31  .net曾宪铭  阅读(4853)  评论(0编辑  收藏  举报