改进篇《不使用反射进行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);  
    }  
  
    /// <summary>  
    /// Abstraction of the function of accessing member of a object at runtime.  
    /// </summary>  
    public interface IMemberAccessor  
    {  
        /// <summary>  
        /// Get the member value of an object.  
        /// </summary>  
        /// <param name="instance">The object to get the member value from.</param>  
        /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>  
        /// <returns>The member value</returns>  
        object GetValue(object instance, string memberName);  
  
        /// <summary>  
        /// Set the member value of an object.  
        /// </summary>  
        /// <param name="instance">The object to get the member value from.</param>  
        /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>  
        /// <param name="newValue">The new value of the property for the object instance.</param>  
        void SetValue(object instance, string memberName, object newValue);  
    }  
  
    internal class PropertyAccessor<T, P> : INamedMemberAccessor  
    {  
        private Func<T, P> m_GetValueDelegate;  
        private Action<T, P> m_SetValueDelegate;  
  
        public PropertyAccessor(PropertyInfo propertyInfo)  
        {  
            Guard.ArgumentNotNull(propertyInfo, "Property can't be null");  
  
            var getMethodInfo = propertyInfo.GetGetMethod();  
            if (null != getMethodInfo)  
            {  
                m_GetValueDelegate = (Func<T, P>)Delegate.CreateDelegate(typeof(Func<T, P>), getMethodInfo);  
            }  
  
            var setMethodInfo = propertyInfo.GetSetMethod();  
            if (null != setMethodInfo)  
            {  
                m_SetValueDelegate = (Action<T, P>)Delegate.CreateDelegate(typeof(Action<T, P>), 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);  
        }  
    }  
  
    /// <summary>  
    /// Singleton, MemberAccessor used to accessing member of a object at runtime.  
    /// </summary>  
    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<string, INamedMemberAccessor> m_accessorCache = new Dictionary<string, INamedMemberAccessor>();  
  
        /// <summary>  
        /// Get the member value of an object.  
        /// </summary>  
        /// <param name="instance">The object to get the member value from.</param>  
        /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>  
        /// <returns>The member value</returns>  
        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);  
.        }  
.  
.        /// <summary>  
.        /// Set the member value of an object.  
.        /// </summary>  
.        /// <param name="instance">The object to get the member value from.</param>  
.        /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>  
.        /// <param name="newValue">The new value of the property for the object instance.</param>  
.        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);
 }

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

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

 internal class PropertyAccessor<T, P> : INamedMemberAccessor
 {
     private Func<T, P> m_GetValueDelegate;
     private Action<T, P> m_SetValueDelegate;

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

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

         var setMethodInfo = propertyInfo.GetSetMethod();
         if (null != setMethodInfo)
         {
             m_SetValueDelegate = (Action<T, P>)Delegate.CreateDelegate(typeof(Action<T, P>), 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);
     }
 }

 /// <summary>
 /// Singleton, MemberAccessor used to accessing member of a object at runtime.
 /// </summary>
 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<string, INamedMemberAccessor> m_accessorCache = new Dictionary<string, INamedMemberAccessor>();

     /// <summary>
     /// Get the member value of an object.
     /// </summary>
     /// <param name="instance">The object to get the member value from.</param>
     /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>
     /// <returns>The member value</returns>
     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);
     }

     /// <summary>
     /// Set the member value of an object.
     /// </summary>
     /// <param name="instance">The object to get the member value from.</param>
     /// <param name="memberName">The member name, could be the name of a property of field. Must be public member.</param>
     /// <param name="newValue">The new value of the property for the object instance.</param>
     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  
  {  
   /// <summary>  
   /// Common guard clauses  
   /// </summary>  
   public static class Guard  
   {  
        /// <summary>  
        /// Checks an argument to ensure it isn't null  
        /// </summary>  
        /// <param name="argumentValue">The argument value to check.</param>  
        /// <param name="argumentName">The name of the argument.</param>  
        public static void ArgumentNotNull(object argumentValue, string argumentName)  
        {  
            if (argumentValue == null)  
            {  
                throw new ArgumentNullException(argumentName);  
            }  
        }  
    }  
    }  


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值