zoukankan      html  css  js  c++  java
  • C# 中特性(Attribute)的使用简介

    Attribute(特性)
    MSDN给出的定义:
      Attribute 类将预定义的系统信息或用户定义的自定义信息与目标元素相关联。目标元素可以是程序集、类、构造函数、委托、枚举、事件、字段、接口、方法、可移植可执行文件模块、参数、属性 (Property)、返回值、结构或其他特性(Attribute)。
    在.Net程序中,可以使用特性(Attribute)来解决许多问题。如:将WebService中接口函数标记为WebMethod,将类标记为可序列化等等。

      此外,我们也可以自定义Attribute,来实现我们需要的功能。但自定义Attribute必须继承自Attribute类。Attribute中有很多方法或者属性,为我们提供了强大的功能。一般我们通过反射的方式来使用Attribute。

    下面结合实际项目中的使用谈谈自己的体会。
    需求:项目中有一个专门的日志库。现在项目中需要前端用到查询、翻页、按各个字段排序等等功能。由于日志数据可能有无效的数据,并且数据量较大。为了提升统计、翻页性能,所以建立了许多临时表。如果在实际操作中为一个一个不同的需求去建立临时表,造成代码大量重复臃肿,并且不便于统一管理,考虑到的方案是通过Attribute的方式,统一建临时表。
    主体思路如下:通过自定义特性来描述要建立临时表的字段的相关类型、长度等等信息,然后通过反射的方式获取这些字段对应的这些特性,然后构造相应的SQL命令就可以完成临时表的建立了。
    特性定义如下:

    [AttributeUsage(AttributeTargets.Property)]
    public class TableFieldAttribute : Attribute
    {
    /// <summary>
    /// 字段长度
    /// </summary>
    public int Length { get; set; }
    
    /// <summary>
    /// 字段描述
    /// </summary>
    public string Describe { get; set; }
    
    /// <summary>
    /// 字段类型
    /// </summary>
    public string Type { get; set; }
    
    }
    

      

    以上AttributeUsage,也是一个继承自Attribute的类,他的作用就是标志自定义类的使用范围,如:字段,属性,类,方法。以及使用我们自定义类
    标记的类的子类是否继承特性等。
    有了这个自定义特性,将它运用到实体上就行了。

    public class TableEntity
    {
    [TableField(Describe = "Guid主键", Length = 36, Type = "uniqueidentifier")]
    public Guid Guid { get; set; }
    
    [TableField(Describe = "名称", Length = 36, Type = "varchar ")]
    public string Name { get; set; }
    }
    

      

    这样在实体定义上,我们就已经有了定义好了数据类型,长度等等。在实际要建临时表时,通过反射要建临时表的实体,便能构造相应的SQL命令了。

    工具类的定义:public class Tools<T> where T : class。实际使用时,将泛型类型换成相应的类型即可。
    主要给出如何使用反射来获取临时表具体字段的信息代码:

    public static List<Record> GetTableFieldsInformation()
    {
    Type t = typeof(T);
    PropertyInfo[] propertyInfos = t.GetProperties();
    List<Record> tableEntities = new List<Record>();
    propertyInfos.ToList().ForEach(property =>
    {
    IList<CustomAttributeData> list = property.GetCustomAttributesData();
    if (list.Count == 1)
    {
    tableEntities.Add(GetTableEntity(list[0].NamedArguments, property));
    }
    else
    {
    throw new Exception();
    }
    });
    return tableEntities;
    }
    

      


    这样, GetTableFieldsInformation()方法中返回的List就是包含了临时表一个字段的所有信息的列表。我们循环列表,构造Sql命令
    主要代码如下:

    recordEntities.ForEach(record =>
    {
    if (i == 0)
    {
    sql = "CREATE TABLE [" + record.TableName + "](";
    }
    if (list.All(item => !record.Type.Equals(item, StringComparison.OrdinalIgnoreCase)))
    {
    sql += string.Format("{0} {1}({2}),", record.FieldName, record.Type, record.Length);
    }
    else
    {
    sql += string.Format("{0} {1},", record.FieldName, record.Type);
    }
    i++;
    });
    

      

    程序最终执行后如下图:


    主要的思想就是这些。另外,如果你细心,你会发现AttributeUsage特性使用和我定义的TableFieldAttribute使用方式上有写不一样。
    TableFieldAttribute的使用方式:[TableField(Describe = "Guid主键", Length = 36, Type = "uniqueidentifier")]
    AttributeUsage的使用方式:[AttributeUsage(AttributeTargets.Property)]。
    同样是自定义的特性,为什么我们定义的和Framework库里的使用不一样呢。?通过Reflect看看AttributeUsage的源码,如下图:

    从图中标记的地方来看,是由于在AttributeUsage中属性的定义【 AttributeTargets ValidOn】以及构造函数的定义不一样导致的。
    有兴趣深入研究的同学可以自己试试。

    后记:特性的使用是很强大的一项功能。本例中使用的仅仅是其他很小的一部分。因此只对在实际应用中做了写说明。另:代码是没有经过细致整理

    代码下载:https://files.cnblogs.com/tyb1222/Attributes.rar

  • 相关阅读:
    Run Shell Commands in Python
    在Linux系统上查找文件
    Build a Beautiful oh-my-zsh Themes
    Build VM Cluster on CentOS Host
    色彩学笔记
    Pr PS 笔记
    pthread 笔记
    图片格式
    win DLL 笔记
    XVS 操作
  • 原文地址:https://www.cnblogs.com/tyb1222/p/2222845.html
Copyright © 2011-2022 走看看