zoukankan      html  css  js  c++  java
  • 非反射不转换类型地动态Property赋值、取值。

    适用情况:

    为一个不确定的对象动态地为某一个未知的Property或多个 Property 赋值和取值

    亮点:

    非 Property.GetValue或 Property.SetValue ,使用委托代理缓存机制。

    因此可以这样用:

    //假设是一个一个Entity对象
    var instance = new Topic();
    //得到其Property Dictionary
    var 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的性能的。
     

  • 相关阅读:
    创建image对象出现内存不足
    错误15023:当前数据库中已存在用户或角色
    看20遍还觉得很搞笑之<麦兜故事>片段之"鱼丸粗面"
    .NET中获取CPU编号及MAC地址
    清空file控件的值
    iframe 父窗口和子窗口的调用方法
    调用javascript后gif动画停止播放
    IIS上无法播放FLV视屏的问题
    黑客和小白
    (转载)innerHTML,innerTEXT,outerHTML的区别
  • 原文地址:https://www.cnblogs.com/darklx/p/2362039.html
Copyright © 2011-2022 走看看