在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过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; }
}
}

测试结果:

Emit优化反射(属性的设置与获取)的更多相关文章

  1. 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调

    [源码下载] 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调 作者: ...

  2. 2017.9.27 JavaWeb 属性的设置和获取

    3.4.3新属性的设置和获取 对于getpParamter方法是通过参数传递获得数据, 设置数据的方法格式: void  request.setAttribute("key",Ob ...

  3. 利用Java反射根据类的名称获取属性信息和父类的属性信息

    代码: import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java ...

  4. storm源码之巧用java反射反序列化clojure的defrecord获取属性值

    [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 storm源 ...

  5. Java设置以及获取JavaBean私有属性进阶

    在上一篇博客中讲到使用Java提供的原生API设置以及获取一个JavaBean的私有属性. 但是使用Java的原生API过于复杂,有没有更加简单的方法呢?答案是肯定的.下面介绍一个开元工具包来非常方便 ...

  6. 封装transform函数(设置和获取transform的属性和属性值)

    (function (w) { /** * 设置或者获取元素的transform属性值 * @param node 要设置的元素 * @param param 变换属性: translate\scal ...

  7. 使用dynamic类型来优化反射

    什么是dynamic类型?微软给出的官方文档中这样解释:在通过 dynamic 类型实现的操作中,该类型的作用是绕过编译时类型检查. 改为在运行时解析这些操作. dynamic 类型简化了对 COM ...

  8. .NET高级特性-Emit(2.2)属性

    关于Emit的博客已经进入第四篇,在读本篇博文之前,我希望读者能先仔细回顾博主之前所编写的关于Emit的博文,从该篇博文开始,我们就可以真正的使用Emit,并把知识转化为实战,我也会把之前的博文链接放 ...

  9. DBGrid 各属性的设置

    在 Delphi 语言的数据库编程中,DBGrid 是显示数据的主要手段之一.但是 DBGrid 缺省的外观未免显得单调和缺乏创意.其实,我们完全可以在我们的程序中通过编程来达到美化DBGrid 外观 ...

随机推荐

  1. Android NDK/JIN 从入门到精通

    1.1 JNI(Java Native Interface) 提供一种Java字节码调用C/C++的解决方案,JNI描述的是一种技术 1.2 NDK(Native Development Kit) A ...

  2. MySQL基本类型、操作

    MySQL 前言(一些废话,可以不看) 为什么学习数据库呢,大家都知道,为了学习删库跑路,因为数据库在工作中起着至关重要的作用,只会写代码的是码农:学好数据库,基本能混口饭吃:在此基础上再学好操作系统 ...

  3. Shell-12-linux信号

    信号类型 信号:信号是在软件层次上对中断机制的一种模拟,通过给一个进程发送信号,执行相应的处理函数 进程可以通过三种方式来响应一个信号: 1.忽略信号,即对信号不做任何处理,其中有两个信号不能忽略: ...

  4. 【原创】JavaFx程序解决Jupyter Notebook导出PDF不显示中文

    0.ATTENTION!!! JavaFx里是通过Java调用控制台执行的的jupyter和xelatex指令, 这些个指令需要在本地安装Jupyter和MikTeX之后才能正常在电脑上运行 1.[问 ...

  5. MongoDB用户创建

    MongoDB采用基于角色的访问控制(RBAC)来确定用户的访问. 授予用户一个或多个角色,确定用户对MongoDB资源的访问权限和用户可以执行哪些操作. 用户应该只有最小权限集才能确保最小权限的系统 ...

  6. C++基于ATL工程编写ActiveX控件步骤

    参考网址: https://blog.csdn.net/whui19890911/article/details/8896554 开发环境:VS2010 开发工程:C++ATL项目 开发目的:创建Ac ...

  7. 因为手机设置字体大小导致h5页面在webview中变形的BUG

    出现这个问题,有以下因素 你的页面采用了rem单位,并且是采用js动态计算html的font-size你的页面被加在了APP中的webview中这该死的手机被重设了字体大小解决方法一般,我们动态计算好 ...

  8. SqlServer 数据库备份到服务器,及删除

    一:备份 1.在数据库管理下 新建一个维护计划,然后下图中点击 标红的按钮 新建计划作业,建好后就可以 SqlServer 代理下的作业里可以看到刚新建的作业. 2.SqlServer 代理下的作业  ...

  9. 分布式链路追踪系统Sleuth和ZipKin

    1.微服务下的链路追踪讲解和重要性 简介:讲解什么是分布式链路追踪系统,及使用好处 进行日志埋点,各微服务追踪. 2.SpringCloud的链路追踪组件Sleuth 1.官方文档 http://cl ...

  10. mysql基础操作(三):数据约束

    首先创建一个数据库 create database homework default character set utf8; use homework; 1.1 默认值约束(default) -- 数 ...