在工作中看到
不使用反射进行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);
}
}
/// <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;
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);
}
}
}
}
本文介绍了一种改进的方法,用于在C#中不使用反射实现属性的动态访问。通过修正原有代码中的缺陷并增强异常处理机制,提高了性能和稳定性。采用单例模式管理属性访问器,适用于需要频繁动态访问属性的场景。

被折叠的 条评论
为什么被折叠?



