public class Order
{
public string OrderId { get; set; }
}
public class SetterWrapper<TTarget, TValue>
{
private Action<TTarget, TValue> _setter;
public SetterWrapper(PropertyInfo propInfo)
{
if (propInfo == null)
throw new ArgumentNullException("propertyInfo");
if (!propInfo.CanWrite)
throw new NotSupportedException("属性是只读或Private Setter");
MethodInfo setMethod = propInfo.GetSetMethod(true);
_setter = (Action<TTarget, TValue>)Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), null, setMethod);
}
public void SetValue(TTarget target, TValue val)
{
if (_setter != null)
{
_setter(target, val);
}
}
}
public class GetterWrapper<TTarget, TValue>
{
private Func<TTarget, TValue> _getter;
public GetterWrapper(PropertyInfo propInfo)
{
if (propInfo == null)
throw new ArgumentNullException("propertyInfo");
if (!propInfo.CanRead)
throw new NotSupportedException("属性是不可读或Private Getter");
MethodInfo getMethod = propInfo.GetGetMethod();
_getter = (Func<TTarget, TValue>)Delegate.CreateDelegate(typeof(Func<TTarget, TValue>), null, getMethod);
}
public TValue GetValue(TTarget target)
{
if (_getter != null)
{
return _getter(target);
}
return default(TValue);
}
}
static void Main(string[] args)
{
Order order=new Order(){OrderId = "W1234566"};
PropertyInfo piInfo = typeof(Order).GetProperty("OrderId");
int maxCount = 1000*1000;
string v = string.Empty;
Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();
for (int i = 0; i < maxCount; i++)
{
order.OrderId = i.ToString();
v = order.OrderId;
}
sw.Stop();
Console.WriteLine("直接访问:{0}", sw.ElapsedTicks);
sw.Reset();
sw.Start();
for (int i = 0; i < maxCount; i++)
{
piInfo.SetValue(order,i.ToString());
v = piInfo.GetValue(order).ToString();
}
sw.Stop();
Console.WriteLine("直接反射:{0}", sw.ElapsedTicks);
sw.Reset();
sw.Start();
GetterWrapper<Order, string> getter = new GetterWrapper<Order, string>(piInfo);
SetterWrapper<Order, string> setter = new SetterWrapper<Order, string>(piInfo);
for (int i = 0; i < maxCount; i++)
{
setter.SetValue(order, i.ToString());
v = getter.GetValue(order);
}
sw.Stop();
Console.WriteLine("泛型妥托反射:{0}", sw.ElapsedTicks);
Console.Read();
}
//win7,vs 2013,8G内存,i5Cpu下测试
Emit反射
public class PropertyHelper { /// <summary> /// Emit获取属性值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="propertyName"></param> /// <returns></returns> public static Func<T, object> EmitGetter<T>(string propertyName) { var type = typeof(T); var property = type.GetProperty(propertyName); var dynamicMethod = new DynamicMethod("get_" + propertyName, typeof(object), new[] { type }, type); var iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Callvirt, property.GetGetMethod()); if (property.PropertyType.IsValueType) { //// 如果是值类型,装箱 iLGenerator.Emit(OpCodes.Box, property.PropertyType); } else { //// 如果是引用类型,转换 iLGenerator.Emit(OpCodes.Castclass, property.PropertyType); } iLGenerator.Emit(OpCodes.Ret); return dynamicMethod.CreateDelegate(typeof(Func<T, object>)) as Func<T, object>; } /// <summary> /// Emit属性值赋值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="propertyName"></param> /// <returns></returns> public static Action<T, object> EmitSetter<T>(string propertyName) { var type = typeof(T); var callMethod = type.GetMethod("set_" + propertyName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic); //// 获取参数 var parameterInfo = callMethod.GetParameters()[0]; var dynamicMethod = new DynamicMethod("EmitCallable", null, new Type[] { type, typeof(object) }, type.Module); var iLGenerator = dynamicMethod.GetILGenerator(); //// 创建一个本地变量,主要用于 Object Type to Propety Type var local = iLGenerator.DeclareLocal(parameterInfo.ParameterType, true); //// 加载第 2 个参数【(T owner, object value)】的 value iLGenerator.Emit(OpCodes.Ldarg_1); if (parameterInfo.ParameterType.IsValueType) { //// 如果是值类型,拆箱 iLGenerator.Emit(OpCodes.Unbox_Any, parameterInfo.ParameterType); } else { //// 如果是引用类型,转换 iLGenerator.Emit(OpCodes.Castclass, parameterInfo.ParameterType); } //// 将上面的拆箱或转换,赋值到本地变量,现在这个本地变量是一个与目标函数相同数据类型的字段了。 iLGenerator.Emit(OpCodes.Stloc, local); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldloc, local); //// 调用函数 iLGenerator.EmitCall(OpCodes.Callvirt, callMethod, null); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod.CreateDelegate(typeof(Action<T, object>)) as Action<T, object>; } }
调用方法
var model=new Persion("张三"); var theName=PropertyHelper.EmitGetter<Persion>("Name")(model);