适用情况:
为一个不确定的对象动态地为某一个未知的Property或多个 Property 赋值和取值
亮点:
非 Property.GetValue或 Property.SetValue ,使用委托代理缓存机制。
因此可以这样用:
//假设是一个一个Entity对象var instance = new Topic();//得到其Property Dictionaryvar propDic = new InstancePropertyDictionary(instance);//无需转换为Object地赋值propDic.SetValue("属性名称",Int32值或Stirng值...);//不存在类型转换地取值Int32 int32Value = propDic.GetInt32("属性名称");string stringValue = propDic.GetString("属性名称");
以下是全部实现的代码,单类,可直接使用:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;namespace Lx{ /// <summary> /// Instance的属性高速读/写(无需转换类型)字典 /// </summary> class InstancePropertyDictionary { /// <summary> /// Get委托 /// </summary> /// <typeparam name="TResult"></typeparam> /// <returns></returns> delegate TResult Get<TResult>(); /// <summary> /// Set委托 /// </summary> /// <typeparam name="TValue"></typeparam> /// <param name="value"></param> delegate void Set<TValue>(TValue value); /// <summary> /// Instance /// </summary> object Target; /// <summary> /// Instance类型 /// </summary> Type TargetType; public InstancePropertyDictionary(object instance) { this.Target = instance; this.TargetType = Target.GetType(); } #region Set委托 /// <summary> /// Key是属性的名字 /// Value是强类型的委托 /// </summary> Dictionary<string, Set<Int32>> setInt32Dic = new Dictionary<string, Set<Int32>>(); Dictionary<string, Set<string>> setStringDic = new Dictionary<string, Set<string>>(); #endregion #region Get委托 Dictionary<string, Get<Int32>> getInt32Dic = new Dictionary<string, Get<Int32>>(); Dictionary<string, Get<string>> getStringDic = new Dictionary<string, Get<string>>(); #endregion /// <summary> /// 装载一个类的属性 /// </summary> public void LoadProperty(params string[] names) { var props = TargetType.GetProperties(); foreach (var name in names) { foreach (var prop in props) { if (prop.Name == name) { CreateGetSet(prop); } } } } /// <summary> /// 创建属性的Getter/Setter委托 /// </summary> /// <param name="property"></param> void CreateGetSet(PropertyInfo property) { string propName = property.Name; var propType = property.PropertyType; var propSetMethod = property.GetSetMethod(); var propGetMethod = property.GetGetMethod(); if (typeof(Int32) == propType) { var set = CreateSet<Int32>(propSetMethod); setInt32Dic.Add(propName, set); var get = CreateGet<Int32>(propGetMethod); getInt32Dic.Add(propName, get); } else if (typeof(string) == propType) { var set = CreateSet<string>(propSetMethod); setStringDic.Add(propName, set); var get = CreateGet<string>(propGetMethod); getStringDic.Add(propName, get); } //剩下的else if请自己实现 } Set<T> CreateSet<T>(MethodInfo methodInfo) { var result = (Set<T>)Delegate.CreateDelegate(typeof(Set<T>), Target, methodInfo); return result; } Get<T> CreateGet<T>(MethodInfo methodInfo) { var result = (Get<T>)Delegate.CreateDelegate(typeof(Get<T>), Target, methodInfo); return result; } /// <summary> /// Set值 /// </summary> /// <param name="propertyName"></param> /// <param name="value"></param> public void SetValue(string propertyName, Int32 value) { //去字典取得强类委托型 var dg = setInt32Dic[propertyName]; dg.Invoke(value); } public void SetValue(string propertyName, string value) { var dg = setStringDic[propertyName]; dg.Invoke(value); } /// <summary> /// Get值 /// </summary> /// <param name="propertyName"></param> /// <returns></returns> public Int32 GetInt32(string propertyName) { var dg = getInt32Dic[propertyName]; return dg.Invoke(); } public string GetString(string propertyName) { var dg = getStringDic[propertyName]; return dg.Invoke(); } }}
我不知道Expression Tree是怎么使用的,是否比创建代理委托性能更好,所以贴出来,欢迎跟帖讨论。
附:
.NET中 Delegate.CreateDelegate方法的实现
[SecuritySafeCritical]public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure){ if (type == null) { throw new ArgumentNullException("type"); } if (method == null) { throw new ArgumentNullException("method"); } if (!(type is RuntimeType)) { throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type"); } RuntimeMethodInfo info = method as RuntimeMethodInfo; if (info == null) { throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "method"); } Type baseType = type.BaseType; if ((baseType == null) || (baseType != typeof(MulticastDelegate))) { throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"), "type"); } Delegate delegate2 = InternalAlloc(type.TypeHandle.GetRuntimeType()); if (delegate2.BindToMethodInfo(firstArgument, info.MethodHandle.GetMethodInfo(), info.GetDeclaringTypeInternal().TypeHandle.GetRuntimeType(), DelegateBindingFlags.RelaxedSignature)) { return delegate2; } if (throwOnBindFailure) { throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth")); } return null;}
我觉得这个类中,影响性能的关键就在于 Delegate.CreateDelegate 方法的具体是怎么做的,难道还是Methodinfo.Invoke(object, object[])吗?
用Reflecter反射发现BindToMethodInfo被标记为 extern了。
关于反对本文所说的“非反射”的:
有人回复说,还是用到反射了。
我这里是说 不采用反射的方式去“动态Property赋值、取值”,本文标题也没有误导吧?
从
CreateSet<T>
CreateGet<T>
这两个方法的实现可以知道,已经不是在用反射了,而是委托
前面用到了反射的地方,只是去取得Property的GetMethod和SetMethod,然后用来创建强类型的委托。
所以在给Property赋值的时候,是不存在反射的。
而且可以看 Secmoo回复 的测试结果,如果在取值、赋值过程中涉及到了反射机制,是决不会有能超过Expression的性能的。
来源:https://www.cnblogs.com/darklx/archive/2012/02/21/2362039.html