C# 中自定义Attribute值的获取与优化

来源:互联网 发布:ios 单向链式编程 编辑:程序博客网 时间:2024/06/06 09:22

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的类

[Name("dept")]    public class CustomAttributes    {        [Name("Deptment Name")]        public string Name { get; set; }        [Name("Deptment 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那个值又是不变的,这样就没必要每次都要进行反射来获取了。基于以上两点代码进行了如下的优化,优化后的代码如下:

public static class CustomAttributeHelper    {         /// <summary>        /// Cache Data        /// </summary>        private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>();        /// <summary>        /// 获取CustomAttribute Value        /// </summary>        /// <typeparam name="T">Attribute的子类型</typeparam>        /// <param name="sourceType">头部标有CustomAttribute类的类型</param>        /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>        /// <returns>返回Attribute的值,没有则返回null</returns>        public static string GetCustomAttributeValue<T>(this Type sourceType, Func<T, string> attributeValueAction) where T : Attribute        {            return GetAttributeValue(sourceType, attributeValueAction, null);        }        /// <summary>        /// 获取CustomAttribute Value        /// </summary>        /// <typeparam name="T">Attribute的子类型</typeparam>        /// <param name="sourceType">头部标有CustomAttribute类的类型</param>        /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>        /// <param name="name">field name或property name</param>        /// <returns>返回Attribute的值,没有则返回null</returns>        public static string GetCustomAttributeValue<T>(this Type sourceType, Func<T, string> attributeValueAction,            string name) where T : Attribute        {            return GetAttributeValue(sourceType, attributeValueAction, name);        }        private static string GetAttributeValue<T>(Type sourceType, Func<T, string> attributeValueAction,            string name) where T : Attribute        {            var key = BuildKey(sourceType, name);            if (!Cache.ContainsKey(key))            {                CacheAttributeValue(sourceType, attributeValueAction, name);            }            return Cache[key];        }        /// <summary>        /// 缓存Attribute Value        /// </summary>        private static void CacheAttributeValue<T>(Type type,            Func<T, string> attributeValueAction, string name)        {            var key = BuildKey(type, name);            var value = GetValue(type, attributeValueAction, name);            lock (key + "_attributeValueLockKey")            {                if (!Cache.ContainsKey(key))                {                    Cache[key] = value;                }            }        }        private static string GetValue<T>(Type type,            Func<T, string> attributeValueAction, string name)        {            object attribute = null;            if (string.IsNullOrEmpty(name))            {                attribute =                    type.GetCustomAttributes(typeof (T), false).FirstOrDefault();            }            else            {                var propertyInfo = type.GetProperty(name);                if (propertyInfo != null)                {                    attribute =                        propertyInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault();                }                var fieldInfo = type.GetField(name);                if (fieldInfo != null)                {                    attribute = fieldInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault();                }            }            return attribute == null ? null : attributeValueAction((T) attribute);        }        /// <summary>        /// 缓存Collection Name Key        /// </summary>        private static string BuildKey(Type type, string name)        {            if (string.IsNullOrEmpty(name))            {                return type.FullName;            }            return type.FullName + "." + name;        }    }

以上优化后的代码:

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

调用方法也更加的简单了,代码如下
var cName=typeof(CustomAttributes).GetCustomAttributeValue<NameAttribute>(x => x.Name);var fName = typeof (CustomAttributes).GetCustomAttributeValue<NameAttribute>(x => x.Name, "Address");
有没有, 是不是很简单,而且调用方式对缓存是完全透明的!







0 0