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

  • A+
所属分类:编程茶楼

 

适用情况:

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

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: