论坛首页 编程语言技术论坛

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

浏览 3175 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-05-30  

 在工作中看到

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

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

这篇文章后觉得很不错!但是在运用其代码的过程中也发现了这个代码存在的一些bug,经过努力,已经把它fix掉了,而且还增加了一个抛出异常的辅助类,现在分享我修改后的代码:

修改了在PropertyAccessor构造时抛出找不到GET SET Method的异常。
此异常的原因是因为有些property没有public Get 或者Set方法,导致propertyInfo.GetGetMethod()/GetSetMethod() 时返回null,继而导致Delegate .CreateDelegate创建失败。

using System;
using System.Collections.Generic;

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

    public interface IMemberAccessor
    {
        object GetValue(object instance, string memberName);
        void SetValue(object instance, string memberName, object newValue);
    }

    internal class PropertyAccessor<T, P> : INamedMemberAccessor
    {
        private Func<T, P> GetValueDelegate;
        private Action<T, P> SetValueDelegate;

        public PropertyAccessor(Type type, string propertyName)
        {
            var propertyInfo = type.GetProperty(propertyName);
            if (null != propertyInfo)
            {
                var getMethodInfo = propertyInfo.GetGetMethod();
                if (null != getMethodInfo)
                { GetValueDelegate = (Func<T, P>)Delegate.CreateDelegate(typeof(Func<T, P>), getMethodInfo); }

                var setMethodInfo = propertyInfo.GetSetMethod();
                if (null != setMethodInfo)
                { SetValueDelegate = (Action<T, P>)Delegate.CreateDelegate(typeof(Action<T, P>), setMethodInfo); }
            }
        }

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

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

    public class MemberAccessor : IMemberAccessor
    {
        #region Singleton
        private MemberAccessor() { }
        public static MemberAccessor Instance
        {
            get { return Nested.instance; }
        }
        private class Nested
        {
            static Nested() { }
            internal static readonly MemberAccessor instance = new MemberAccessor();
        }
        #endregion

        private static Dictionary<string, INamedMemberAccessor> accessorCache = new Dictionary<string, INamedMemberAccessor>();

        public object GetValue(object instance, string memberName)
        {
            return FindAccessor(instance, memberName).GetValue(instance);
        }

        public void SetValue(object instance, string memberName, object newValue)
        {
            FindAccessor(instance, memberName).SetValue(instance, newValue);
        }

        private INamedMemberAccessor FindAccessor(object instance, string memberName)
        {
            Type type = instance.GetType();
            string key = type.FullName + memberName;
            INamedMemberAccessor accessor;
            if (!accessorCache.TryGetValue(key, out accessor) && accessor == null)
            {
                accessor = Activator.CreateInstance(typeof(PropertyAccessor<,>).MakeGenericType(type, type.GetProperty(memberName).PropertyType), type, memberName) as INamedMemberAccessor;
                Guard.ArgumentNotNull(accessor, "accessor");
                accessorCache.Add(key, accessor);
            }
            return accessor;
        }
    }
}

 

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)
            {
                var ex = new ArgumentNullException(argumentName);
            }
        }
    }
}

 

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics