改进篇《不使用反射进行C#属性的运行时动态访问》

在运用其代码的过程中也发现了这个代码存在的一些bug,经过努力,已经把它fix掉了,现在分享我修改后的代码:Dictionary只放存在的类和属性的 GET、SET委托:
 
<类+属性名, 对应的GET、SET委托>如果类名或者属性名不存在,则不会给添加到这个单列的Dictionary中。
 
1.修改了在PropertyAccessor构造时抛出找不到GET SET Method的异常。此异常的原因是因为有些property没有public Get 或者Set方法,
导致propertyInfo.GetGetMethod()/GetSetMethod() 时返回null,继而导致Delegate .CreateDelegate创建失败。
 2.增加了一个抛异常的辅助类,增强了异常处理机制。
3.将MemberAccessor 设计成为单列模式,增加性能,方便调用。
4.经过测试,没有引入其他bug。
using System;  
 using System.Collections.Generic;  
 using System.Reflection;  
 
 namespace XXX.Common  
 {  
   internal interface INamedMemberAccessor  
   {  
       object GetValue(object instance);  
        void SetValue(object instance, object newValue);  
    }  
  
    ///   
    /// Abstraction of the function of accessing member of a object at runtime.  
    ///   
    public interface IMemberAccessor  
    {  
        ///   
        /// Get the member value of an object.  
        ///   
        /// The object to get the member value from.  
        /// The member name, could be the name of a property of field. Must be public member.  
        /// The member value  
        object GetValue(object instance, string memberName);  
  
        ///   
        /// Set the member value of an object.  
        ///   
        /// The object to get the member value from.  
        /// The member name, could be the name of a property of field. Must be public member.  
        /// The new value of the property for the object instance.  
        void SetValue(object instance, string memberName, object newValue);  
    }  
  
    internal class PropertyAccessor : INamedMemberAccessor  
    {  
        private Func m_GetValueDelegate;  
        private Action m_SetValueDelegate;  
  
        public PropertyAccessor(PropertyInfo propertyInfo)  
        {  
            Guard.ArgumentNotNull(propertyInfo, "Property can't be null");  
  
            var getMethodInfo = propertyInfo.GetGetMethod();  
            if (null != getMethodInfo)  
            {  
                m_GetValueDelegate = (Func)Delegate.CreateDelegate(typeof(Func), getMethodInfo);  
            }  
  
            var setMethodInfo = propertyInfo.GetSetMethod();  
            if (null != setMethodInfo)  
            {  
                m_SetValueDelegate = (Action)Delegate.CreateDelegate(typeof(Action), setMethodInfo);  
            }  
        }  
  
        public object GetValue(object instance)  
        {  
            Guard.ArgumentNotNull(m_GetValueDelegate, "The Property doesn't have GetMethod");  
            return m_GetValueDelegate((T)instance);  
        }  
  
        public void SetValue(object instance, object newValue)  
        {  
            Guard.ArgumentNotNull(m_SetValueDelegate, "The Property doesn't have SetMethod");  
            m_SetValueDelegate((T)instance, (P)newValue);  
        }  
    }  
  
    ///   
    /// Singleton, MemberAccessor used to accessing member of a object at runtime.  
    ///   
    public class MemberAccessor : IMemberAccessor  
    {  
        #region Singleton  
        private MemberAccessor() { }  
        public static MemberAccessor Instance  
        {  
            get { return Nested.m_instance; }  
        }  
        private class Nested  
        {  
            static Nested() { }  
            internal static readonly MemberAccessor m_instance = new MemberAccessor();  
        }  
        #endregion  
  
        private static Dictionary m_accessorCache = new Dictionary();  
  
        ///   
        /// Get the member value of an object.  
        ///   
        /// The object to get the member value from.  
        /// The member name, could be the name of a property of field. Must be public member.  
        /// The member value  
        public object GetValue(object instance, string memberName)  
        {  
            INamedMemberAccessor ma = FindAccessor(instance, memberName);  
            Guard.ArgumentNotNull(ma, "The instance doesn't have this property");  
.            return ma.GetValue(instance);  
.        }  
.  
.        ///   
.        /// Set the member value of an object.  
.        ///   
.        /// The object to get the member value from.  
.        /// The member name, could be the name of a property of field. Must be public member.  
.        /// The new value of the property for the object instance.  
.        public void SetValue(object instance, string memberName, object newValue)  
.        {  
.            INamedMemberAccessor ma = FindAccessor(instance, memberName);  
.            Guard.ArgumentNotNull(ma, "The instance doesn't have this property");  
.            ma.SetValue(instance, newValue);  
.        }  
.  
.        private INamedMemberAccessor FindAccessor(object instance, string memberName)  
.        {  
.            Type type = instance.GetType();  
.            string key = type.FullName + memberName;  
.  
.            INamedMemberAccessor accessor = null;  
.            if (!m_accessorCache.TryGetValue(key, out accessor))  
.            {  
.                #region bug fix from Ambiguous Match Exception  
.                PropertyInfo propInfo = type.GetProperty(memberName, BindingFlags.DeclaredOnly |  
.                                    BindingFlags.Public | BindingFlags.NonPublic |  
.                                    BindingFlags.Instance);  
.                if (null == propInfo)  
.                {  
.                    propInfo = type.GetProperty(memberName);  
.                }  
.                #endregion  
.                if (null == propInfo)  
.                {  
.                    return null;  
.                }  
.                else  
.                {  
.                    accessor = Activator.CreateInstance(typeof(PropertyAccessor<,>).MakeGenericType(type, propInfo.PropertyType), propInfo) as INamedMemberAccessor;  
.                    m_accessorCache.Add(key, accessor);  
.                }  
.            }  
.            return accessor;  
.        }  
.    }  
.	}  
		using System;
		using System.Collections.Generic;
		using System.Reflection;

		namespace XXX.Common
	{
 internal interface INamedMemberAccessor
 {
     object GetValue(object instance);
     void SetValue(object instance, object newValue);
 }

 /// 
 /// Abstraction of the function of accessing member of a object at runtime.
 /// 
 public interface IMemberAccessor
 {
     /// 
     /// Get the member value of an object.
     /// 
     /// The object to get the member value from.
     /// The member name, could be the name of a property of field. Must be public member.
     /// The member value
     object GetValue(object instance, string memberName);

     /// 
     /// Set the member value of an object.
     /// 
     /// The object to get the member value from.
     /// The member name, could be the name of a property of field. Must be public member.
     /// The new value of the property for the object instance.
     void SetValue(object instance, string memberName, object newValue);
 }

 internal class PropertyAccessor : INamedMemberAccessor
 {
     private Func m_GetValueDelegate;
     private Action m_SetValueDelegate;

     public PropertyAccessor(PropertyInfo propertyInfo)
     {
         Guard.ArgumentNotNull(propertyInfo, "Property can't be null");

         var getMethodInfo = propertyInfo.GetGetMethod();
         if (null != getMethodInfo)
         {
             m_GetValueDelegate = (Func)Delegate.CreateDelegate(typeof(Func), getMethodInfo);
         }

         var setMethodInfo = propertyInfo.GetSetMethod();
         if (null != setMethodInfo)
         {
             m_SetValueDelegate = (Action)Delegate.CreateDelegate(typeof(Action), setMethodInfo);
         }
     }

     public object GetValue(object instance)
     {
         Guard.ArgumentNotNull(m_GetValueDelegate, "The Property doesn't have GetMethod");
         return m_GetValueDelegate((T)instance);
     }

     public void SetValue(object instance, object newValue)
     {
         Guard.ArgumentNotNull(m_SetValueDelegate, "The Property doesn't have SetMethod");
         m_SetValueDelegate((T)instance, (P)newValue);
     }
 }

 /// 
 /// Singleton, MemberAccessor used to accessing member of a object at runtime.
 /// 
 public class MemberAccessor : IMemberAccessor
 {
     #region Singleton
     private MemberAccessor() { }
     public static MemberAccessor Instance
     {
         get { return Nested.m_instance; }
     }
     private class Nested
     {
         static Nested() { }
         internal static readonly MemberAccessor m_instance = new MemberAccessor();
     }
     #endregion

     private static Dictionary m_accessorCache = new Dictionary();

     /// 
     /// Get the member value of an object.
     /// 
     /// The object to get the member value from.
     /// The member name, could be the name of a property of field. Must be public member.
     /// The member value
     public object GetValue(object instance, string memberName)
     {
         INamedMemberAccessor ma = FindAccessor(instance, memberName);
         Guard.ArgumentNotNull(ma, "The instance doesn't have this property");
         return ma.GetValue(instance);
     }

     /// 
     /// Set the member value of an object.
     /// 
     /// The object to get the member value from.
     /// The member name, could be the name of a property of field. Must be public member.
     /// The new value of the property for the object instance.
     public void SetValue(object instance, string memberName, object newValue)
     {
         INamedMemberAccessor ma = FindAccessor(instance, memberName);
         Guard.ArgumentNotNull(ma, "The instance doesn't have this property");
         ma.SetValue(instance, newValue);
     }

     private INamedMemberAccessor FindAccessor(object instance, string memberName)
     {
         Type type = instance.GetType();
         string key = type.FullName + memberName;

         INamedMemberAccessor accessor = null;
         if (!m_accessorCache.TryGetValue(key, out accessor))
         {
             #region bug fix from Ambiguous Match Exception
             PropertyInfo propInfo = type.GetProperty(memberName, BindingFlags.DeclaredOnly |
                                 BindingFlags.Public | BindingFlags.NonPublic |
                                 BindingFlags.Instance);
             if (null == propInfo)
             {
                 propInfo = type.GetProperty(memberName);
             }
             #endregion
             if (null == propInfo)
             {
                 return null;
             }
             else
             {
                 accessor = Activator.CreateInstance(typeof(PropertyAccessor<,>).MakeGenericType(type, propInfo.PropertyType), propInfo) as INamedMemberAccessor;
                 m_accessorCache.Add(key, accessor);
             }
         }
         return accessor;
     }
  }
 }
 


  C#代码 
  using System;  
 
 namespace XXX.Common  
  {  
   ///   
   /// Common guard clauses  
   ///   
   public static class Guard  
   {  
        ///   
        /// Checks an argument to ensure it isn't null  
        ///   
        /// The argument value to check.  
        /// The name of the argument.  
        public static void ArgumentNotNull(object argumentValue, string argumentName)  
        {  
            if (argumentValue == null)  
            {  
                throw new ArgumentNullException(argumentName);  
            }  
        }  
    }  
    }  


 

你可能感兴趣的:(改进篇《不使用反射进行C#属性的运行时动态访问》)