在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过Emit技术优化反射来提高获取和设置属性值的效率

一、实现代码:

    /// <summary>
/// 设置器委托
/// </summary>
/// <param name="target"></param>
/// <param name="arg"></param>
public delegate void SetValueDelegate(object target, object arg);
/// <summary>
/// 访问器委托
/// </summary>
/// <param name="target">目标对象</param>
/// <returns></returns>
public delegate object GetValueDelegate(object target); public static class DynamicMethodFactory
{
/// <summary>
/// 获取访问器
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
public static GetValueDelegate GetGetter(this PropertyInfo property)
{
return DynamicMethodFactory.CreatePropertyGetter(property);
}
/// <summary>
/// 获取设置器
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
public static SetValueDelegate GetSetter(this PropertyInfo property)
{
return DynamicMethodFactory.CreatePropertySetter(property);
} private static SetValueDelegate CreatePropertySetter(PropertyInfo property)
{
if (property == null)
{
throw new ArgumentNullException("property");
} if (!property.CanWrite)
{
return null;
} MethodInfo setMethod = property.GetSetMethod(true); DynamicMethod dm = new DynamicMethod("PropertySetter", null,
new Type[] { typeof(object), typeof(object) }, property.DeclaringType, true); ILGenerator il = dm.GetILGenerator(); if (!setMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
}
il.Emit(OpCodes.Ldarg_1); EmitCastToReference(il, property.PropertyType);
if (!setMethod.IsStatic && !property.DeclaringType.IsValueType)
{
il.EmitCall(OpCodes.Callvirt, setMethod, null);
}
else
{
il.EmitCall(OpCodes.Call, setMethod, null);
} il.Emit(OpCodes.Ret); return (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));
}
private static GetValueDelegate CreatePropertyGetter(PropertyInfo property)
{
if (property == null)
{
throw new ArgumentNullException("property");
} if (!property.CanRead)
{
return null;
} MethodInfo getMethod = property.GetGetMethod(true); DynamicMethod dm = new DynamicMethod("PropertyGetter", typeof(object), new[] { typeof(object) }, property.DeclaringType, true); Type returnType = getMethod.ReturnType;
ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
EmitCastToReference(il, getMethod.DeclaringType); if (getMethod.IsFinal)
{
il.Emit(OpCodes.Call, getMethod);
}
else
{
il.Emit(OpCodes.Callvirt, getMethod);
} if (returnType.IsValueType)
{
il.Emit(OpCodes.Box, returnType);
} il.Emit(OpCodes.Ret);
il.Emit(OpCodes.Ret); return (GetValueDelegate)dm.CreateDelegate(typeof(GetValueDelegate));
}
private static void EmitCastToReference(ILGenerator il, Type type)
{
if (type.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, type);
}
else
{
il.Emit(OpCodes.Castclass, type);
}
}
}

二、测试代码:

#define SETTER
//#define GETTER using System;
using System.Diagnostics;
using System.Reflection; namespace PublishConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
// 输出当前运行时
Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion()); // 通过最顶端的预编译符号(SETTER/GETTER)控制测试的代码块 // 调用100w次时间比较
int count = 100_0000;
// 测试次数
int testTimes = 5;
OrderInfo testObj = new OrderInfo() { OrderID = 123 };
PropertyInfo propInfo = typeof(OrderInfo).GetProperty("OrderID"); for (int k = 0; k < testTimes; k++)
{
#if SETTER
Stopwatch watch1 = Stopwatch.StartNew(); Console.WriteLine($"------------- 设置器测试 ------------- ");
for (int i = 0; i < count; i++)
{
testObj.OrderID = 1;
} watch1.Stop();
Console.WriteLine($"直接设置花费时间: {watch1.Elapsed.TotalMilliseconds} 毫秒"); //////////////////////////////////////////////////// var setter = propInfo.GetSetter();
Stopwatch watch2 = Stopwatch.StartNew(); for (int i = 0; i < count; i++)
{
setter(testObj, 2);
} watch2.Stop();
Console.WriteLine($"EmitSet设置花费时间: {watch2.Elapsed.TotalMilliseconds} 毫秒"); //////////////////////////////////////////////////// Stopwatch watch3 = Stopwatch.StartNew(); for (int i = 0; i < count; i++)
{
propInfo.SetValue(testObj, 3, null);
} watch3.Stop();
Console.WriteLine($"纯反射设置花费时间:  {watch3.Elapsed.TotalMilliseconds} 毫秒"); //////////////////////////////////////////////////// Console.WriteLine("-------------------");
// 设置器
Console.WriteLine("纯反射/直接设置:{0} / {1} = {2}",
watch3.Elapsed.TotalMilliseconds.ToString(),
watch1.Elapsed.TotalMilliseconds.ToString(),
watch3.Elapsed.TotalMilliseconds / watch1.Elapsed.TotalMilliseconds); Console.WriteLine("纯反射/EmitSet:{0} / {1} = {2}",
watch3.Elapsed.TotalMilliseconds.ToString(),
watch2.Elapsed.TotalMilliseconds.ToString(),
watch3.Elapsed.TotalMilliseconds / watch2.Elapsed.TotalMilliseconds); Console.WriteLine("EmitSet/直接设置:{0} / {1} = {2}",
watch2.Elapsed.TotalMilliseconds.ToString(),
watch1.Elapsed.TotalMilliseconds.ToString(),
watch2.Elapsed.TotalMilliseconds / watch1.Elapsed.TotalMilliseconds);
#endif #if GETTER Console.WriteLine($"------------- 访问器测试 ------------- ");
Stopwatch watch4 = Stopwatch.StartNew(); for (int i = 0; i < count; i++)
{
var orderId = testObj.OrderID;
} watch4.Stop();
Console.WriteLine($"直接访问花费时间:  {watch4.Elapsed.TotalMilliseconds} 毫秒"); ////////////////////////////////////////////////////
testObj.OrderID = 4;
var getter = propInfo.GetGetter();
Stopwatch watch5 = Stopwatch.StartNew(); for (int i = 0; i < count; i++)
{
var orderId = getter(testObj);
} watch5.Stop();
Console.WriteLine($"EmitSet访问花费时间: {watch5.Elapsed.TotalMilliseconds} 毫秒"); //////////////////////////////////////////////////// testObj.OrderID = 5;
Stopwatch watch6 = Stopwatch.StartNew(); for (int i = 0; i < count; i++)
{
var orderId = propInfo.GetValue(testObj);
} watch6.Stop();
Console.WriteLine($"纯反射访问花费时间:  {watch6.Elapsed.TotalMilliseconds} 毫秒"); //////////////////////////////////////////////////// Console.WriteLine("-------------------"); // 访问器
Console.WriteLine("纯反射/直接设置:{0} / {1} = {2}",
watch6.Elapsed.TotalMilliseconds.ToString(),
watch4.Elapsed.TotalMilliseconds.ToString(),
watch6.Elapsed.TotalMilliseconds / watch4.Elapsed.TotalMilliseconds); Console.WriteLine("纯反射/EmitSet:{0} / {1} = {2}",
watch6.Elapsed.TotalMilliseconds.ToString(),
watch5.Elapsed.TotalMilliseconds.ToString(),
watch6.Elapsed.TotalMilliseconds / watch5.Elapsed.TotalMilliseconds); Console.WriteLine("EmitSet/直接设置:{0} / {1} = {2}",
watch5.Elapsed.TotalMilliseconds.ToString(),
watch4.Elapsed.TotalMilliseconds.ToString(),
watch5.Elapsed.TotalMilliseconds / watch4.Elapsed.TotalMilliseconds);
#endif
} //Console.WriteLine("Hello World!");
Console.ReadKey();
}
} public class OrderInfo
{
public int OrderID { get; set; }
}
}

测试结果:

最新文章

  1. 【转】ORACLE的REDO与UNDO
  2. XmlRpc.net 出参字符串还原为结构体
  3. linux–nohup命令(转)
  4. ECSHOP MYSQL 公用类库中的autoExecute方法
  5. [原]素数筛法【Sieve Of Eratosthenes + Sieve Of Euler】
  6. 【HTML】Intermediate2:Text: AbbreviationsQuotations Code
  7. iOS应用审核的通关秘籍
  8. DevExpress GridView使用技巧之列标题点击事件
  9. ELK+Filebeat 集中式日志解决方案详解
  10. 微信h5,背景音乐自动播放
  11. Spring中Model、ModelMap及ModelAndView之间的区别+传递参数
  12. npm run build 打包后(直接打包白屏),如何运行在本地查看效果(Apache服务)
  13. PHPMailer命令执行及任意文件读取漏洞
  14. logstash实战tcp插件
  15. Java内部类引用外部类中的局部变量为何必须是final问题解析
  16. sitemap
  17. MYSQL三种安装方式--二进制包安装
  18. C# 6.0 新特性 (四)
  19. MyBatis---自动创建表
  20. 2 27re.py

热门文章

  1. 密码三次就会锁掉 while 循环
  2. 这个 Redis 连接池的新监控方式针不戳~我再加一点佐料
  3. 墙裂推荐!2020Android阿里&amp;腾讯&amp;百度&amp;字节&amp;美团校招面试汇总
  4. 9419页最新一线互联网Android面试题解析大全
  5. C++面向对象总结——虚指针与虚函数表
  6. Kong网关安装之Docker版(2)
  7. VRRP的基本配置
  8. 百度地图开发-引入地图SDK并配置 02
  9. 【Openxml】将Openxml的椭圆弧线arcTo转为Svg的椭圆弧线
  10. WPF---依赖属性(二)