Emit优化反射(属性的设置与获取)
在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过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优化反射(属性的设置与获取)的更多相关文章
- 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调
[源码下载] 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调 作者: ...
- 2017.9.27 JavaWeb 属性的设置和获取
3.4.3新属性的设置和获取 对于getpParamter方法是通过参数传递获得数据, 设置数据的方法格式: void request.setAttribute("key",Ob ...
- 利用Java反射根据类的名称获取属性信息和父类的属性信息
代码: import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java ...
- storm源码之巧用java反射反序列化clojure的defrecord获取属性值
[原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 storm源 ...
- Java设置以及获取JavaBean私有属性进阶
在上一篇博客中讲到使用Java提供的原生API设置以及获取一个JavaBean的私有属性. 但是使用Java的原生API过于复杂,有没有更加简单的方法呢?答案是肯定的.下面介绍一个开元工具包来非常方便 ...
- 封装transform函数(设置和获取transform的属性和属性值)
(function (w) { /** * 设置或者获取元素的transform属性值 * @param node 要设置的元素 * @param param 变换属性: translate\scal ...
- 使用dynamic类型来优化反射
什么是dynamic类型?微软给出的官方文档中这样解释:在通过 dynamic 类型实现的操作中,该类型的作用是绕过编译时类型检查. 改为在运行时解析这些操作. dynamic 类型简化了对 COM ...
- .NET高级特性-Emit(2.2)属性
关于Emit的博客已经进入第四篇,在读本篇博文之前,我希望读者能先仔细回顾博主之前所编写的关于Emit的博文,从该篇博文开始,我们就可以真正的使用Emit,并把知识转化为实战,我也会把之前的博文链接放 ...
- DBGrid 各属性的设置
在 Delphi 语言的数据库编程中,DBGrid 是显示数据的主要手段之一.但是 DBGrid 缺省的外观未免显得单调和缺乏创意.其实,我们完全可以在我们的程序中通过编程来达到美化DBGrid 外观 ...
随机推荐
- css伪类(:before和:after)
:before和:after的作用就是在指定的元素内容(而不是元素本身)之前或者之后插入一个包含content属性指定内容的行内元素,最基本的用法如下: #example{ width:300p ...
- linux笔记全(无图版)
1.ls 查看当前目录下的所有内容 黑色的是文件,蓝色的是文件夹,也就是目录 2.rm -f anaconda-ks. cfg 彻底删除文件(如不确定,则需要先保存备份,也就是快照) 3.ifconf ...
- C++ 封装类 2 设计一个学生类 属性有姓名学号 可以给姓名 和学号赋值 可以显示学生的姓名和学号
1 //设计一个学生类 属性有姓名学号 可以给姓名 和学号赋值 可以显示学生的姓名和学号 2 #include <iostream> 3 #include<string> 4 ...
- 关于表单重复提交之验证码 和谷歌Kaptcha图片验证码的使用
表单重复提交之-----验证码 表单重复提交有三种常见的情况: 一:提交完表单.服务器使用请求转来进行页面跳转.这个时候,用户按下功能键 F5,就会发起最后一次的请求. 造成表单重复提交问题.解决方法 ...
- Linux 基础学习篇笔记 Linux基础知识
哎呀,翻到第一篇,映出眼帘的标题:从Unix到Linux(我就知道学习不能急,不能像我,看个简介,就赶忙去查了,原来作者在这里给出详细的介绍了) 1.1根据书上写的,原来linux的内核是被Linus ...
- redis的五大数据类型实现原理
1.对象的类型与编码 Redis使用前面说的五大数据类型来表示键和值,每次在Redis数据库中创建一个键值对时,至少会创建两个对象,一个是键对象,一个是值对象,而Redis中的每个对象都是由 redi ...
- SQLFlow:用户注册
#### 一.SQLFlow是什么 随着大数据技术的发展与普及,数据治理和数据质量变得越来越重要,数据血缘分析在业界悄然兴起并得到了广泛流行,今天推荐一款专业且易用的血缘分析工具--SQLFlow.据 ...
- .Net Core WebApi(二)
查看当前端口暴露的所有接口信息 https://localhost:5001/.well-known/openid-configuration 拿到信息如下
- Longhorn 云原生容器分布式存储 - Air Gap 安装
内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 云原生容器分布式存储 - 设计架构和概念 Longhorn 云原生容器分布式存储 - ...
- 目录-理解ASP.NET Core
<理解ASP.NET Core>基于.NET5进行整理,旨在帮助大家能够对ASP.NET Core框架有一个清晰的认识. 目录 [01] Startup [02] Middleware [ ...