C#自定义Attribute值的获取是开发中会经常用到的,一般我们的做法也就是用反射进行获取的,代码也不是很复杂。

1、首先有如下自定义的Attribute

     [AttributeUsage(AttributeTargets.All)]
public sealed class NameAttribute : Attribute
{
private readonly string _name; public string Name
{
get { return _name; }
} public NameAttribute(string name)
{
_name = name;
}
}

  2、定义一个使用NameAttribute的类

[Description("Customer Information")]
[Name("customer_info")]
public class CustomerInfo
{
[Name("name")]
public string Name { get; set; } [Name("address")]
public string Address;
}

 

  3、获取CustomAttributes类上的"dept"也就很简单了

         private static string GetName()
{
var type = typeof(CustomAttributes); var attribute = type.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); if (attribute == null)
{
return null;
} return ((NameAttribute)attribute).Name;
}

  以上代码就可以简单的获取,类上的Attribute的值了,但是需求往往不是这么简单的,不仅要获取类头部Attribute上的值,还要获取字段Address头部Attribute上的值。有的同学可能就觉得这还不简单呀,直接上代码

         private static string GetAddress()
{
var type = typeof (CustomAttributes); var fieldInfo = type.GetField("Address");
if (fieldInfo == null)
{
return null;
} var attribute = fieldInfo.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); if (attribute == null)
{
return null;
} return ((NameAttribute) attribute).Name;
}

  上面代码就是获取Address字段头部上的Attribute值了。虽然我们是获取到了我们想要的,但是我们发现这样做是不是太累了,如果又扩展一个自定义的Attribute,或者又在一个新的属性或字段上标上Attribute时,我们又要写一段代码来实现我想要的,这些严重代码违反了DRY的设计原则。我们知道获取Attribute是通过反射来取的,Attribute那个值又是不变的,这样就没必要每次都要进行反射来获取了。基于以上两点代码进行了如下的优化,优化后的代码如下:

 using System;
using System.Collections.Concurrent;
using System.Reflection; public static class CustomAttributeExtensions
{
/// <summary>
/// Cache Data
/// </summary>
private static readonly ConcurrentDictionary<string, object> Cache = new ConcurrentDictionary<string, object>(); /// <summary>
/// 获取CustomAttribute Value
/// </summary>
/// <typeparam name="TAttribute">Attribute的子类型</typeparam>
/// <typeparam name="TReturn">TReturn的子类型</typeparam>
/// <param name="sourceType">头部标有CustomAttribute类的类型</param>
/// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
/// <returns>返回Attribute的值,没有则返回null</returns>
public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction)
where TAttribute : Attribute
{
return _getAttributeValue(sourceType, attributeValueAction, null);
} /// <summary>
/// 获取CustomAttribute Value
/// </summary>
/// <typeparam name="TAttribute">Attribute的子类型</typeparam>
/// <typeparam name="TReturn">TReturn的子类型</typeparam>
/// <param name="sourceType">头部标有CustomAttribute类的类型</param>
/// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
/// <param name="propertyName">field name或property name</param>
/// <returns>返回Attribute的值,没有则返回null</returns>
public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction, string propertyName)
where TAttribute : Attribute
{
return _getAttributeValue(sourceType, attributeValueAction, propertyName);
} #region private methods private static TReturn _getAttributeValue<TAttribute, TReturn>(Type sourceType, Func<TAttribute, TReturn> attributeFunc, string propertyName)
where TAttribute : Attribute
{
var cacheKey = BuildKey<TAttribute>(sourceType, propertyName);
var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName));
if (value is TReturn) return (TReturn)Cache[cacheKey];
return default(TReturn);
} private static string BuildKey<TAttribute>(Type type, string propertyName) where TAttribute : Attribute
{
var attributeName = typeof(TAttribute).FullName;
if (string.IsNullOrEmpty(propertyName))
{
return type.FullName + "." + attributeName;
} return type.FullName + "." + propertyName + "." + attributeName;
} private static TReturn GetValue<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> attributeValueAction, string name)
where TAttribute : Attribute
{
TAttribute attribute = default(TAttribute);
if (string.IsNullOrEmpty(name))
{
attribute = type.GetCustomAttribute<TAttribute>(false);
}
else
{
var propertyInfo = type.GetProperty(name);
if (propertyInfo != null)
{
attribute = propertyInfo.GetCustomAttribute<TAttribute>(false);
}
else
{
var fieldInfo = type.GetField(name);
if (fieldInfo != null)
{
attribute = fieldInfo.GetCustomAttribute<TAttribute>(false);
}
}
} return attribute == null ? default(TReturn) : attributeValueAction(attribute);
} #endregion
}

  优化后的代码:

  把不同的代码用泛型T,Fun<TAttribute,TReturn>来处理来减少重复的代码;
  把取过的Attribute值存到一个ConcurrentDictionary中,下次再来取时,如果有则直接取ConcurrentDictionary中的值,如果没有才通过反射来取相应的Attribute值,这样大大的提高效率;

  调用方法也更加的简单了,代码如下:

            var customerInfoName = typeof(CustomerInfo).GetCustomAttributeValue<NameAttribute, string>(x => x.Name);
var customerAddressName = typeof(CustomerInfo).GetCustomAttributeValue<NameAttribute, string>(x => x.Name, "Address");
var customerInfoDesc = typeof(CustomerInfo).GetCustomAttributeValue<DescriptionAttribute, string>(x => x.Description); Console.WriteLine("CustomerInfo Name:" + customerInfoName);
Console.WriteLine("customerInfo >Address Name:" + customerAddressName);
Console.WriteLine("customerInfo Desc:" + customerInfoDesc);

  运行结果:

  如果你有什么好的或不好的意见欢迎拍砖!

  谢谢大家的建议,己经更新(2019/11/21)

  Code:Download

C#自定义Attribute值的获取与优化的更多相关文章

  1. .net c#获取自定义Attribute

    前言: 在c#开发中,有时候我们需要读取 Attribute中的信息(关于Attribute , 我自己把他理解成一个可以为类,属性标记的东西,这个标记可以为你提供一些关于类,方法,属性的额外信息) ...

  2. 转:C#制作ORM映射学习笔记一 自定义Attribute类

    之前在做unity项目时发现只能用odbc连接数据库,感觉非常的麻烦,因为之前做web开发的时候用惯了ORM映射,所以我想在unity中也用一下ORM(虽然我知道出于性能的考虑这样做事不好的,不过自己 ...

  3. 【MVC 笔记】MVC 自定义 Attribute 属性中的猫腻

    原想在 MVC Action 上加一个自定义 Attribute 来做一些控制操作,最先的做法是在自定 Attribute 中定义一个属性来做逻辑判断,可惜事与愿违,这个属性值居然会被缓存起来,于是于 ...

  4. Django项目:CRM(客户关系管理系统)--14--06PerfectCRM实现King_admin注册功能获取内存优化处理

    <th >{% get_app_name admin_class.model %}{{ admin_class }} </th> #kingadmin_tags.py # —— ...

  5. XsdGen:通过自定义Attribute与反射自动生成XSD

    前言 系统之间的数据交互往往需要事先定义一些契约,在WCF中我们需要先编写XSD文件,然后通过自动代码生成工具自动生成C#对象.对于刚刚接触契约的人来说,掌握XMLSpy之类的软件之后确实比手写XML ...

  6. 自定义Attribute 服务端校验 客户端校验

    MVC 自定义Attribute 服务端校验 客户端校验/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) *//* Autho ...

  7. 从值栈获取List集合

    -------------------siwuxie095 从值栈获取 List 集合 1.具体步骤 (1)在 Action 中向值栈放 List 集合 (2)在 JSP 页面中从值栈获取 List ...

  8. 使用c#特性,给方法或类打自定义标签再反射获取

    给方法打自定义标签再反射获取 1.自定义特性类 using System; using System.Collections; using System.Collections.Generic; // ...

  9. map自定义键值类型

    map自定义键值类型 改变Map的默认比较方式 https://www.cnblogs.com/zjfdlut/archive/2011/08/12/2135698.html 大家知道,STL中的ma ...

随机推荐

  1. 【转】Nginx配置文件详细说明

    Nginx配置文件详细说明 在此记录下Nginx服务器nginx.conf的配置文件说明, 部分注释收集与网络. #运行用户user www-data;    #启动进程,通常设置成和cpu的数量相等 ...

  2. 深度围观block:第三集

    深度围观block:第三集 发布于:2013-07-12 10:09阅读数:7804 本文是深度围观block的第三篇文章,也是最后一篇.希望读者阅读了之后,对block有更加深入的理解,同时也希望之 ...

  3. Golang http包下FileServer的使用

    FileServer文档:https://godoc.org/net/http#FileServer 今天看到http的 Handle 方法,所以就像试试,就找到FileServer FileServ ...

  4. 用TMS的控件就可以了,有bug叫他们改

    [深圳]大宝delphi本身不是太隐定.不建议弄太多自己的东西.还要debug好长时间.为了快.便不去弄控件了够用了.真的.都不用花太多时间去弄这弄那.有bug叫他们改便可以.

  5. vijos国庆节模拟赛之繁星春水

    A.闪烁的繁星 题目:https://vijos.org/p/1881 题解:貌似做过小白逛公园或者序列操作都可以秒出吧,就是pushup函数比较麻烦,不过仔细想一想就知道了. 代码: #includ ...

  6. HDU4742----Pinball Game 3D(三维LIS、CDQ分治)

    题意:三维空间内 n个小球,对应坐标(x,y,z).输出LIS的长度以及方案数. 首先可以先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之 ...

  7. linux mysql默认安装在哪个目录

    MySQL安装完成后不象SQL Server默认安装在一个目录,它的数据库文件.配置文件和命令文件分别在不同的目录,了解这些目录非常重要,尤其对于Linux的初学者,因为 Linux本身的目录结构就比 ...

  8. Spring 基于注解零配置开发

    本文是转载文章,感觉比较好,如有侵权,请联系本人,我将及时删除. 原文网址:< Spring 基于注解零配置开发 > 一:搜索Bean 再也不用在XML文件里写什么配置信息了. Sprin ...

  9. android 多项对话框

    在main.xml中 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...

  10. MAVEN Scope使用

    在Maven的依赖管理中,经常会用到依赖的scope设置.这里整理下各种scope的使用场景和说明,以及在使用中的实践心得.Scope的使用场景和说明1.compile编译范围,默认scope,在工程 ...