日期:2014-05-18  浏览次数:20741 次

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

?在工作中看到

不使用反射进行C#属性的运行时动态访问:

http://www.cnblogs.com/nankezhishi/archive/2012/02/11/dynamicaccess.html

这篇文章后觉得很不错!但是在运用其代码的过程中也发现了这个代码存在的一些bug,经过努力,已经把它fix掉了,现在分享我修改后的代码:
Dictionary只放存在的类和属性的 GET、SET委托:
<key???????? ,??Value>
<类+属性名,??对应的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);