非反射不转换类型地动态Property赋值、取值。

落花浮王杯 提交于 2020-01-20 14:54:09

 

适用情况:

为一个不确定的对象动态地为某一个未知的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的性能的。
 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!