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

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");
有没有, 是不是很简单,而且调用方式对缓存是完全透明的!







  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值