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
    { 
        /// 
        /// Cache Data
        /// 
        private static readonly Dictionary Cache = new Dictionary();

        /// 
        /// 获取CustomAttribute Value
        /// 
        /// Attribute的子类型
        /// 头部标有CustomAttribute类的类型
        /// 取Attribute具体哪个属性值的匿名函数
        /// 返回Attribute的值,没有则返回null
        public static string GetCustomAttributeValue(this Type sourceType, Func attributeValueAction) where T : Attribute
        {
            return GetAttributeValue(sourceType, attributeValueAction, null);
        }

        /// 
        /// 获取CustomAttribute Value
        /// 
        /// Attribute的子类型
        /// 头部标有CustomAttribute类的类型
        /// 取Attribute具体哪个属性值的匿名函数
        /// field name或property name
        /// 返回Attribute的值,没有则返回null
        public static string GetCustomAttributeValue(this Type sourceType, Func attributeValueAction,
            string name) where T : Attribute
        {
            return GetAttributeValue(sourceType, attributeValueAction, name);
        }

        private static string GetAttributeValue(Type sourceType, Func attributeValueAction,
            string name) where T : Attribute
        {
            var key = BuildKey(sourceType, name);
            if (!Cache.ContainsKey(key))
            {
                CacheAttributeValue(sourceType, attributeValueAction, name);
            }

            return Cache[key];
        }

        /// 
        /// 缓存Attribute Value
        /// 
        private static void CacheAttributeValue(Type type,
            Func 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(Type type,
            Func 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);
        }

        /// 
        /// 缓存Collection Name Key
        /// 
        private static string BuildKey(Type type, string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return type.FullName;
            }

            return type.FullName + "." + name;
        }
    }
以上优化后的代码:

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

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







你可能感兴趣的:(C#)