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


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

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

     1     [AttributeUsage(AttributeTargets.All)]
     2     public sealed class NameAttribute : Attribute
     3     {
     4         private readonly string _name;
     5 
     6         public string Name
     7         {
     8             get { return _name; }
     9         }
    10 
    11         public NameAttribute(string name)
    12         {
    13             _name = name;
    14         }
    15     }

      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"也就很简单了

     1         private static string GetName()
     2         {
     3             var type = typeof(CustomAttributes);
     4 
     5             var attribute = type.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault();
     6 
     7             if (attribute == null)
     8             {
     9                 return null;
    10             }
    11 
    12             return ((NameAttribute)attribute).Name;
    13         }

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

     1         private static string GetAddress()
     2         {
     3             var type = typeof (CustomAttributes);
     4 
     5             var fieldInfo = type.GetField("Address");
     6             if (fieldInfo == null)
     7             {
     8                 return null;
     9             }
    10 
    11             var attribute = fieldInfo.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault();
    12 
    13             if (attribute == null)
    14             {
    15                 return null;
    16             }
    17 
    18             return ((NameAttribute) attribute).Name;
    19         }

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

     1 using System;
     2 using System.Collections.Concurrent;
     3 using System.Reflection;
     4 
     5 public static class CustomAttributeExtensions
     6 {
     7     /// <summary>
     8     /// Cache Data
     9     /// </summary>
    10     private static readonly ConcurrentDictionary<string, object> Cache = new ConcurrentDictionary<string, object>();
    11 
    12     /// <summary>
    13     /// 获取CustomAttribute Value
    14     /// </summary>
    15     /// <typeparam name="TAttribute">Attribute的子类型</typeparam>
    16     /// <typeparam name="TReturn">TReturn的子类型</typeparam>
    17     /// <param name="sourceType">头部标有CustomAttribute类的类型</param>
    18     /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
    19     /// <returns>返回Attribute的值,没有则返回null</returns>
    20     public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction)
    21         where TAttribute : Attribute
    22     {
    23         return _getAttributeValue(sourceType, attributeValueAction, null);
    24     }
    25 
    26     /// <summary>
    27     /// 获取CustomAttribute Value
    28     /// </summary>
    29     /// <typeparam name="TAttribute">Attribute的子类型</typeparam>
    30     /// <typeparam name="TReturn">TReturn的子类型</typeparam>
    31     /// <param name="sourceType">头部标有CustomAttribute类的类型</param>
    32     /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
    33     /// <param name="propertyName">field name或property name</param>
    34     /// <returns>返回Attribute的值,没有则返回null</returns>
    35     public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction, string propertyName)
    36         where TAttribute : Attribute
    37     {
    38         return _getAttributeValue(sourceType, attributeValueAction, propertyName);
    39     }
    40 
    41     #region private methods
    42 
    43     private static TReturn _getAttributeValue<TAttribute, TReturn>(Type sourceType, Func<TAttribute, TReturn> attributeFunc, string propertyName)
    44         where TAttribute : Attribute
    45     {
    46         var cacheKey = BuildKey<TAttribute>(sourceType, propertyName);
    47         var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName));
    48         if (value is TReturn) return (TReturn)Cache[cacheKey];
    49         return default(TReturn);
    50     }
    51 
    52     private static string BuildKey<TAttribute>(Type type, string propertyName) where TAttribute : Attribute
    53     {
    54         var attributeName = typeof(TAttribute).FullName;
    55         if (string.IsNullOrEmpty(propertyName))
    56         {
    57             return type.FullName + "." + attributeName;
    58         }
    59 
    60         return type.FullName + "." + propertyName + "." + attributeName;
    61     }
    62 
    63     private static TReturn GetValue<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> attributeValueAction, string name)
    64         where TAttribute : Attribute
    65     {
    66         TAttribute attribute = default(TAttribute);
    67         if (string.IsNullOrEmpty(name))
    68         {
    69             attribute = type.GetCustomAttribute<TAttribute>(false);
    70         }
    71         else
    72         {
    73             var propertyInfo = type.GetProperty(name);
    74             if (propertyInfo != null)
    75             {
    76                 attribute = propertyInfo.GetCustomAttribute<TAttribute>(false);
    77             }
    78             else
    79             {
    80                 var fieldInfo = type.GetField(name);
    81                 if (fieldInfo != null)
    82                 {
    83                     attribute = fieldInfo.GetCustomAttribute<TAttribute>(false);
    84                 }
    85             }
    86         }
    87 
    88         return attribute == null ? default(TReturn) : attributeValueAction(attribute);
    89     }
    90 
    91     #endregion
    92 }

      优化后的代码:

      把不同的代码用泛型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

  • 相关阅读:
    arcgis10.2转shp文件中文乱码问题解决方案
    Android Context作为参数传递this
    andriod inputbox
    andriod inputType
    《ArcGIS Runtime SDK for Android开发笔记》——(5)、基于Android Studio构建ArcGIS Android开发环境(离线部署)(转)
    终于理解了什么是LGPL
    产品经理如何与强势的技术沟通? 技术比较有资历,会以技术无法实现等方面的原因拒绝处理产品提出的需求。 你们是否遇到这样的技术? 产品懂技术的话,是不是会好一些,因为可以和技术说“行话”了,并且产品懂技术就不会被忽悠了。
    Core Dump总结
    LIBRARY_PATH是编译时候用的,LD_LIBRARY_PATH是程序运行是使用的
    如何禁止C++默认成员函数
  • 原文地址:https://www.cnblogs.com/junjieok/p/4949806.html
Copyright © 2020-2023  润新知