在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过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. JS基础-数据类型判断typeof、instanceof、Object.prototype.toString

    typeof用在基本数据类型和函数时,返回其对应类型的描述,对于引用类型都返回为object. instanceof无法判断基本数据类型,对于引用类型数据,返回其其对应类型. Object.proto ...

  2. Mysql数据库基础知识(全)

    前言:本博文为个人笔记,记录了Mysql的一些基本操作,一般掌握本博文就可以了解数据库.表.数据项的增删改查,希望对大家的学习有所帮助. 首先下载PHPSTUDY,将Mysql配置为系统变量. 具体操 ...

  3. “入职一年,那个被高薪挖来的Android开发被劝退了。”

    其实,在很多小伙伴的想法中,是希望通过跳槽实现薪酬涨幅,可是跳槽不是冲动后决定,应该谨慎啊~ 01 我的学弟,最近向我吐槽,2020 年上半年入职一家公司,当时是高薪挖走的他,所谓钱到位,工作也是充满 ...

  4. 冲击BATZ!GitHub近8.3K+的Android进阶指南,面试再也不愁了

    过去十年是移动互联网蓬勃发展的黄金期,相信每个人也都享受到了移动互联网红利,在此期间,移动互联网经历了曙光期.成长期.成熟期.现在来说已经进入饱和期. 依然记得在 2010-2013 年期间,从事移动 ...

  5. 『Java』StringBuilder类使用方法

    String类存在的问题 String类的底层是一个被final修饰的byte[],不能改变. 为了解决以上问题,可以使用java.lang.StringBuilder类. StringBuilder ...

  6. vue服务端渲染之nuxtjs

    前言 本篇主要针对nuxtjs中的一些重要概念整理和代码实现! 在学习vue服务端渲染之前,先搞清楚几个概念: 什么是客户端渲染(CSR) 什么是服务端渲染(SSR) CSR和SSR有什么异同 客户端 ...

  7. Linux远程访问控制

    目录 一.SSH远程管理 1.1.定义 1.2.配置OpenSSH服务端 二.sshd服务支持两种验证方式 2.1.密码验证 2.2.使用SSH客户端程序 ssh远程登录 scp远程复制 sftp安全 ...

  8. Pikachu-Over Permission模块

    一.概述 如果使用A用户的权限去操作B用户的数据,A的权限小于B的权限,如果能够成功操作,则称之为越权操作. 越权漏洞形成的原因是后台使用了 不合理的权限校验规则导致的. 一般越权漏洞容易出现在权限页 ...

  9. Sqli-Labs less17-19

    less-17 前置基础知识: UPDATEXML (XML_document, XPath_string, new_value); 第一个参数:XML_document是String格式,为XML文 ...

  10. 对象 绑定关系 隐藏属性 property 继承

    绑定方法两种: 1.绑定给对象的 class Student(): country = 'CHINA' def __init__(self,name,age): self.name = name se ...