Hello World
Spiga

Fast Reflection Library

2009-02-01 09:25 by 老赵, 13715 visits

全文英文版:Fast Reflection Library

这是我在CodePlex上创建的一个项目,它的网址是http://www.codeplex.com/FastReflectionLib,使用Microsoft Public License (Ms-PL),您可以随意在自己的产品中使用它的全部或部分代码。这个项目用到了我在《方法的直接调用,反射调用与Lambda表达式调用》和《这下没理由嫌Eval的性能差了吧?》两篇文章里用到的做法,并加以提炼和扩展发布的项目——随便搞搞,留个印记,也供以后参考。

基本使用方式

反射是.NET中非常重要的功能。使用反射来构造对象、调用方法或是访问属性是某些项目中常用的做法之一(例如ORM框架)。众所周知,与一个成员的直接访问相比,反射调用的性能要低好几个数量级。FastReflectionLib提供了一种简便的方式,使一些常用反射调用的性能得到大幅提高。如下:

using System;
using System.Reflection;
using FastReflectionLib;

namespace SimpleConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            PropertyInfo propertyInfo = typeof(string).GetProperty("Length");
            MethodInfo methodInfo = typeof(string).GetMethod("Contains");

            string s = "Hello World!";

            // get value by normal reflection
            int length1 = (int)propertyInfo.GetValue(s, null);
            // get value by the extension method from FastReflectionLib,
            // which is much faster
            int length2 = (int)propertyInfo.FastGetValue(s);

            // invoke by normal reflection
            bool result1 = (bool)methodInfo.Invoke(s, new object[] { "Hello" });
            // invoke by the extension method from FastReflectionLib,
            // which is much faster
            bool result2 = (bool)methodInfo.FastInvoke(s, new object[] { "Hello" });
        }
    }
}

在得到了PropertyInfo或MethodInfo对象之后,我们可以使用GetValue或Invoke方法来访问属性或调用方法。在FastReflectionLib中为PropertyInfo、MethodInfo等对象定义了对应的扩展方法,于是我们就可以使用这些扩展方法(从代码上看来,基本上只是在原来的方法之前加上“Fast”)来进行调用,与之前的方法相比,新的扩展方法性能有极大的提高。

直接使用各工作对象

各FastXxx方法实际上是将PropertyInfo等对象作为Key去一个Cache中获取对应的工作对象,然后调用工作对象上对应的方法。因此,直接调用工作对象可以获得更好的性能。各工作对象类型的对应关系如下:

  • PropertyInfo:IPropertyAccessor
  • MethodInfo:IMethodInvoker
  • ConstructorInfo:IConstructorInvoker
  • FieldInfo:IFieldAccessor

我们可以使用FastReflectionCaches.MethodInvokerCache来获取一个IMethodInvoker对象:

static void Execute(MethodInfo methodInfo, object instance, int times)
{ 
    IMethodInvoker invoker = FastReflectionCaches.MethodInvokerCache.Get(methodInfo);
    object[] parameters = new object[0];
    for (int i = 0; i < times; i++)
    {
        invoker.Invoke(instance, parameters);
    }
}

工作对象的默认实现与扩展

在FastReflectionLib中,已经提供了IPropertyAccessor等接口的默认实现。该实现将会构造一颗表达式树(Expression Tree)并将其编译(调用其Compile方法)以获得一个与反射方法签名相同的委托对象。这是一种简单、通用而安全的实现,由于Compile方法使用了Emit,其性能也较为令人满意(可见下面的性能测试)。但是这并不是性能最高的做法,如果使用Emit生成最优化的代码,其性能甚至会高于方法的直接调用(例如Dynamic Reflection Library)。如果您想使用更好的实现来替换,则可以自行构造一个工作对象接口的实现,并替换对应的Factory:

public class BetterPropertyAccessor : IPropertyAccessor
{
    public BetterPropertyAccessor(PropertyInfo propertyInfo) { ... }

    ...
}

public class BetterPropertyAccessorFactory :
    IFastReflectionFactory<PropertyInfo, IPropertyAccessor>
{
    public IPropertyAccessor Create(PropertyInfo key)
    {
        return new BetterPropertyAccessor(key);
    }
}

class Program
{
    static void Main(string[] args)
    {
        FastReflectionFactories.PropertyAccessorFactory =
            new BetterPropertyAccessorFactory();

        ...
    }
}

缓存的默认实现与扩展

在FastReflectionLib中使用基于System.Collections.Generic.Dictionary类型编写的缓存容器。每次调用FastXxx扩展方法时,类库将从对应的缓存容器中获取工作对象。如果缓存容器中还没有所需的工作对象,那么它就会调用合适的Factory来构造新的工作对象。从下面的性能测试来看,许多时间是消耗在缓存查找上的,如果您有更好的缓存实现,可以使用以下的方法替换默认的缓存的容器:

public class BetterMethodInvokerCache :
    IFastReflectionCache<MethodInfo, IMethodInvoker>
{
    public IMethodInvoker Get(MethodInfo key) { ... }
}

class Program
{
    static void Main(string[] args)
    {
        FastReflectionCaches.MethodInvokerCache = 
            new BetterMethodInvokerCache();

        ...
    }
}

根据需要自行缓存工作对象

FastReflectionLib中通过PropertyInfo等对象作为Key,对PropertyAccessor等工作对象进行缓存。但是在某些场景下,您也可以选择合适的方式来自行缓存工作对象。与FastReflectionLib源码同时发布的CustomCache示例网站中包含了一个FastEval扩展,在某些场景下,我们可以使用这个更高效的方法来替换内置的Eval方法。这个示例的特点如下:

  • 使用对象的类型和属性名同时作为缓存的Key获取对应的PropertyAccessor对象
  • 使用PropertyAccessor获取“匿名对象”中的属性值
  • 缓存的作用域为特定页面,而不是整个AppDomain。

性能测试

FastReflectionLib源码中包含了一个性能测试项目,您可以从中看出FastReflectionLib对于反射的性能改进。摘录部分数据如下(测试在我的笔记本上运行,Release编译)。

执行以下方法:

public class Test
{
    public void MethodWithArgs(int a1, string a2) { }
}

进行一百万次调用,结果如下:

调用方式 消耗时间(秒)
方法直接调用 0.0071397
内置反射调用 1.4936181
工作对象调用 0.0468326
Fast方法调用 0.1373712
Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

71 条回复

  1. 萧寒
    *.*.*.*
    链接

    萧寒 2009-01-31 22:50:00

    好东西,收藏

  2. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-31 22:51:00

    哈哈不知道是不是沙发呢。
    这般文章好像是你英文文章的翻译版本是吧。我关注了那篇英文文章
    看到了一半就不行了。不懂的单词太多。主要是对于这些技术上的东西懂的太少
    关注一下。看看中文的先

  3. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-31 22:51:00

    哎~!一个板凳
    老赵好像天天晚上在线

  4. gyf19[未注册用户]
    *.*.*.*
    链接

    gyf19[未注册用户] 2009-01-31 22:53:00

    不错,.net2.0 可以使用吗

  5. 老赵
    admin
    链接

    老赵 2009-01-31 22:55:00

    --引用--------------------------------------------------
    天生俪姿: 哈哈不知道是不是沙发呢。
    这般文章好像是你英文文章的翻译版本是吧。我关注了那篇英文文章
    看到了一半就不行了。不懂的单词太多。主要是对于这些技术上的东西懂的太少
    关注一下。看看中文的先
    --------------------------------------------------------
    忘了放我的英文链接了……今天懒得改了,明天放。

  6. 老赵
    admin
    链接

    老赵 2009-01-31 22:56:00

    --引用--------------------------------------------------
    gyf19: 不错,.net2.0 可以使用吗
    --------------------------------------------------------
    不可以

  7. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-31 22:56:00

    问下老赵这个东西是你自己搞的吗?
    源自哪里?我说不是指你在Code Plex 做的什么。

  8. 老赵
    admin
    链接

    老赵 2009-01-31 22:56:00

    --引用--------------------------------------------------
    天生俪姿: 哎~!一个板凳
    老赵好像天天晚上在线
    --------------------------------------------------------
    对于stateless的系统来说,老赵一直在线的,嘿嘿

  9. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-01-31 22:57:00

    很棒,呀哈!

  10. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-31 23:01:00

    stateless
    这个词原来是 无国藉的意思。
    哎~!还好去了谷歌查了一下
    这个是3.5 的产物是吧。
    能下载的东东是全部的代码吗?

  11. 老赵
    admin
    链接

    老赵 2009-01-31 23:03:00

    --引用--------------------------------------------------
    天生俪姿: 问下老赵这个东西是你自己搞的吗?
    源自哪里?我说不是指你在Code Plex 做的什么。
    --------------------------------------------------------
    自己搞得,源自.NET 3.5中Lamda Expression的Compile功能,呵呵。

  12. 老赵
    admin
    链接

    老赵 2009-01-31 23:04:00

    --引用--------------------------------------------------
    天生俪姿: stateless
    这个词原来是 无国藉的意思。
    哎~!还好去了谷歌查了一下
    这个是3.5 的产物是吧。
    能下载的东东是全部的代码吗?
    --------------------------------------------------------
    嗯,全部代码,包括性能测试和一个示例。

  13. 重典
    *.*.*.*
    链接

    重典 2009-01-31 23:23:00

    downloading
    支持一下

    看了看测试感觉效果不错

  14. 老赵
    admin
    链接

    老赵 2009-02-01 00:04:00

    @重典
    恩,够用了

  15. virusplayer[未注册用户]
    *.*.*.*
    链接

    virusplayer[未注册用户] 2009-02-01 00:40:00

    老赵的东西
    支持一下

  16. 张柔
    *.*.*.*
    链接

    张柔 2009-02-01 00:42:00

    听上去很不错的样子

    我想问一个问题

    我项目里三层的数据层用到了反射工厂
    我感觉查询一多的话会频繁调用反射工厂

    有必要做优化吗

  17. 老赵
    admin
    链接

    老赵 2009-02-01 00:45:00

    --引用--------------------------------------------------
    virusplayer: 老赵的东西
    支持一下
    --------------------------------------------------------
    恩,谢谢

  18. 老赵
    admin
    链接

    老赵 2009-02-01 00:45:00

    @张柔
    任何性能上的猜测都要通过profiler来检验才能说明问题。

  19. 张柔
    *.*.*.*
    链接

    张柔 2009-02-01 00:50:00

    @Jeffrey Zhao
    这个东西都没有涉及过

    是不是IDE里的分析-启动性能向导

  20. 老赵
    admin
    链接

    老赵 2009-02-01 01:00:00

    @张柔
    都可以,自己插入计算代码也可以。

  21. 梁逸晨
    *.*.*.*
    链接

    梁逸晨 2009-02-01 02:55:00

    老赵,问个和主题不相关的:

    1 codeplex支不支持SVN?或者类似的VSS那些都行,只要能备份代码就行了。
    2 如果能够备份,有没有那种不允许公共查看源码的功能?


    烧了几块硬盘了,再也不敢相信本地主机的安全性。目前在用googlecode,但是强制面向公共开源,有点项目又不太合适这么做。

  22. Anders Liu
    *.*.*.*
    链接

    Anders Liu 2009-02-01 07:37:00

    @梁逸晨

    一看代码的目录结构就知道老赵用的是svn bridge。强人,我一直用TFC的……

    开源,就是开放远爱吗,不允许公共查看,还叫啥开源啊。

    老赵一看也是设计模式控,回头仔细研究一下。

  23. kkun
    *.*.*.*
    链接

    kkun 2009-02-01 09:21:00

    标记!学习!谢谢!

  24. 老赵
    admin
    链接

    老赵 2009-02-01 09:28:00

    @梁逸晨
    svn可以的,不能不开放——当然可以让你存30天

  25. 老赵
    admin
    链接

    老赵 2009-02-01 09:29:00

    @Anders Liu
    习惯svn了阿,client也是现成的,不会用tfc了……
    // 这嘎达没有啥设计模式的

  26. Tony Qu
    *.*.*.*
    链接

    Tony Qu 2009-02-01 10:00:00

    不错,不过不知道封装之后性能到底如何,有待考证:p

  27. 老赵
    admin
    链接

    老赵 2009-02-01 10:09:00

    @Tony Qu
    什么东西封装之后?

  28. Zealic
    *.*.*.*
    链接

    Zealic 2009-02-01 10:28:00

    除了直接反射(性能最差的) 和直接调用
    其他技术的实现都是基于 DynamicMethod 实现。
    包括所谓的 Dynamic Reflection Library。
    其实这样的工作已经有很多的实现。

    比如
    NHibernate 的 NHibernate.Property
    IBatis.Net 的 IBatisNet.Common.Utilities.Objects.Members
    似乎 Spring.Net 中也有,这点就懒得验证了。

    当然,知道这么多是因为我自己也写过这样的东西。
    完善以后就发出来。

  29. 老赵
    admin
    链接

    老赵 2009-02-01 10:59:00

    @Zealic
    不错——幸好这个Lambda做法没人搞过。

  30. 真见
    *.*.*.*
    链接

    真见 2009-02-01 12:10:00

    我看了,在weblogs上也写过了。。

  31. --[未注册用户]
    *.*.*.*
    链接

    --[未注册用户] 2009-02-01 17:13:00

    我想知道如何申请Weblogs的地址?

  32. Kolor
    *.*.*.*
    链接

    Kolor 2009-02-02 10:58:00

    其实,这个类库在反射的性能提升上,主要就是使用了cache,适用于同一(相同引用,因为cache的存储结构是以对象为Key的字典)PropertyInfo或者MethodInfo等的多次(比如object类型属性的Get操作,调用次数在600次以上才有性能提升)反射调用,在这种情况下,性能得以提升,而且随着调用次数的增加,性能会得到更大的提升;但是如果只是一次调用的话,结果只会适得其反,比起正常的反射调用,性能要慢大概两个数量级。 所以说,少量调用还是不建议使用这个类库,不知道我说的对不对 另外,我对Lambda不是很熟,楼主能说下在这个类库中使用Lambda的好处吗?对比其他方法,它有什么优势呢?

  33. 老赵
    admin
    链接

    老赵 2009-02-02 11:28:00

    @Kolor
    嗯?不是阿,是方法调用的开销上的提高,不是cache获取和GetMethod方法性能上的差距。
    用Lambda表达式的好处就是方便,安全,清晰。

  34. Kolor
    *.*.*.*
    链接

    Kolor 2009-02-02 11:52:00

    @Jeffrey Zhao
    你的设计应该是,第一次调用取得工作方法,并把它放入cache,下次直接从cache取,所以性能上有提升,是这样的吧? 你调低循环次数times,再看看测试结果

  35. 老赵
    admin
    链接

    老赵 2009-02-02 12:24:00

    @Kolor
    构造一个MethodInvoker自然比直接调用一次MethodInfo要慢。
    你可以比较一下“内置反射调用”与“工作对象调用”性能的差距,这才是最大的优化。

  36. Chester
    *.*.*.*
    链接

    Chester 2009-02-03 01:48:00

    Very good. But I think you could get rid of factory layer and name cache as factory.

  37. 老赵
    admin
    链接

    老赵 2009-02-03 09:48:00

    @Chester
    为什么,完全不一样的东西,现在可以单独替换cache和factory实现,两个东西完全是正交的。

  38. Chester
    *.*.*.*
    链接

    Chester 2009-02-04 01:50:00

    It is only my preference as I don't see much value for one extra layer and the cache is only a performance sweetener. I assume no one would replace it. Instead I would like to see a simpler design. That's it. Thanks anyway. One more thing is parameter type conversion. For example, if I have a method: void Method(double d) While calling it like this: Method(1). The generated method will throw InvalidCastException. I used to use Convert.ChangeType to convert the type of parameter value while in reflection calls.

  39. 老赵
    admin
    链接

    老赵 2009-02-04 09:03:00

    @Chester
    嗯,多谢提醒,我看看是不是要用Convert.ChangeType去做。
    不过cache,我觉得现在cache消耗还是蛮大的,以后应该有方法,或者有需要去替换它。

  40. 大 兵
    *.*.*.*
    链接

    大 兵 2009-02-05 09:12:00

    好东西,拿回去研究下。

  41. guozili[未注册用户]
    *.*.*.*
    链接

    guozili[未注册用户] 2009-02-12 20:08:00

    看了看代码,和你想法差不多,有几点疑问:

    1. 动态构建lambda expression性能消耗好像是在lambda.Compile(),所以把每个Compile后的Func缓存起来。

    2. 动态创建lambda expression是否在运行期也会编译成中间代码,最终和手写Emit本质一样,只不过构造expression代码清晰安全易懂。

  42. guozili[未注册用户]
    *.*.*.*
    链接

    guozili[未注册用户] 2009-02-12 20:12:00

    3. 另外你这个如果应用在orm里datatable -> 实体,如果表或字段一多,cache的键值对是相当的庞大吧,不知道有没有更好的方法。

  43. 老赵
    admin
    链接

    老赵 2009-02-12 21:23:00

    @guozili
    可以尽量减少缓存项——而且其实好的数据结构还是一样的,不会影响性能。

  44. googleman
    *.*.*.*
    链接

    googleman 2009-02-22 08:30:00

    老赵好!

    我的您的一位忠实观众朱先忠(googleman)。想向您请教一个问题(其实,很早就有这个想法),是关于微软ASP.NET AJAX客户端框架的未来前途的。

  45. lightning[未注册用户]
    *.*.*.*
    链接

    lightning[未注册用户] 2009-03-29 23:59:00

    其实可以使用委托的...这样的话,性能会提高很多,而且能工作在.NET 2.0上

  46. 老赵
    admin
    链接

    老赵 2009-03-30 00:08:00

    @lightning
    如果您能看一下文章的内容再回复我会很感激的……

  47. lightning[未注册用户]
    *.*.*.*
    链接

    lightning[未注册用户] 2009-04-01 20:26:00

    @Jeffrey Zhao
    其实我的意思是一些静态方法和属性,可以直接用Delegate.CreateDelegate创建委托

  48. 老赵
    admin
    链接

    老赵 2009-04-01 22:59:00

    --引用--------------------------------------------------
    lightning: @Jeffrey Zhao
    其实我的意思是一些静态方法和属性,可以直接用Delegate.CreateDelegate创建委托
    --------------------------------------------------------
    这和静态不静态有什么关系……你还是没有看清这个解决方案的作用,我再举个例子吧。
    Delegate.CreateDelegate的作用是什么呢?是把R Method(T1, T2, T3)变成一个Func<T1, T2, T3, R>的委托对象,但是这又有什么用呢?调用起来还是必须依次传递对象,不能替代反射的作用。
    反射的接口是什么呢?object Invoke(object instance, object[] args),可以把参数作为数组传入,得到结果,这个是最灵活的动态调用,很多情况下无可避免。我的解决方案,就是保持这种调用方法不变的情况下,大大提高性能。
    因此,我还是希望您可以仔细看一下文章,以及它引用的内容,这样可以避免很多误会……

  49. lightning[未注册用户]
    *.*.*.*
    链接

    lightning[未注册用户] 2009-04-02 20:11:00

    @Jeffrey Zhao
    但是在很多情况下,我们是知道实例类型,还有参数类型和返回值类型的,这样不如直接使用泛型委托

  50. 老赵
    admin
    链接

    老赵 2009-04-02 20:17:00

    @lightning
    1、我没有听懂你的意思。
    2、就算是“很多时候”像你说的那样,那么我的解决方案就是面向另外一种功能的——您说这么多的意义何在呢?既然不能替代,为什么说我的做法“不如XXXX”?

    真的,希望您可以仔细看一下文章再评论,这些解释都是可以省下的,最没有意义的口舌之争……

  51. kyorry
    *.*.*.*
    链接

    kyorry 2009-04-07 08:54:00

    老赵,您很长时间没去更新了,什么时候能发布一个1.0版本啊,后来您又做了一个性能计数器,下一版本Sample会不会也加进去

  52. 信徒~[未注册用户]
    *.*.*.*
    链接

    信徒~[未注册用户] 2009-09-09 18:40:00

    老赵 真乃神人也 膜拜!

  53. 小No
    *.*.*.*
    链接

    小No 2009-11-20 12:41:00

    @Jeffrey Zhao
    老赵,有个老外用了你这个组件之后啊,发了一张帖子说你这个组件在多线程下有可能有问题

    以下是这个帖子的地址:
    http://fastreflectionlib.codeplex.com/Thread/View.aspx?ThreadId=48730

    老赵不知道你看过没有,能不能确认一下是否有这个问题

  54. 老赵
    admin
    链接

    老赵 2009-11-20 13:10:00

    @小No
    很久以前的问题了,现在没问题。

  55. 小No
    *.*.*.*
    链接

    小No 2009-11-20 14:31:00

    @Jeffrey Zhao
    OK, 谢谢!!

  56. 链接

    duanseven 2010-05-11 21:46:42

    不知道CodePlex是不是最新版本的。发现FieldAccessor初始化,没有构建委托。

  57. 老赵
    admin
    链接

    老赵 2010-05-11 23:51:18

    @duanseven

    不妨自己修改一下,呵呵。

  58. MS.SEEN
    58.248.230.*
    链接

    MS.SEEN 2010-05-25 19:00:02

    好像MethodInvoker不支持 out 参数 或者是 ref 参数.

  59. mrlen
    59.61.238.*
    链接

    mrlen 2010-06-11 14:08:17

    我很想知道……如果我要对 “私有”进行调用、赋值呢?

  60. delphidoc
    124.254.58.*
    链接

    delphidoc 2010-11-12 10:52:55

    挺好的东西,怎么不继续往下做了?

  61. delphidoc
    180.77.82.*
    链接

    delphidoc 2010-12-04 22:52:58

    今天仔细看了一下你的库,又测试了一下,我发现PropertyAccessor中的SetValue是用MethodInvoker实现的,我测了一下,如果把这个方法改为用Lambda来实现速度可以再快一倍以上.

  62. 老赵
    admin
    链接

    老赵 2010-12-05 00:34:16

    @delphidoc

    这是一定的。写这篇文章的时候是.NET 3.5,还不能用Expression写语句,到了.NET 4.0就没问题了。

  63. 链接

    培华 2011-02-18 16:25:10

    老赵什么时候把这类库用4.0重构一遍就好了

  64. 链接

    培华 2011-04-26 09:53:57

    老赵,在多线程环境下用你的这个类库出现问题了,抛nullreference.

    在MethodInvoker.cs文件的这个方法里面。

    public object Invoke(object instance, params object[] parameters)
    {
        return this.m_invoker(instance, parameters);
    }
    

    有什么办法解决吗?

  65. 老赵
    admin
    链接

    老赵 2011-04-26 20:56:46

    @培华

    我这个支持多线程的,一直在用,你哪里用错了吧。

  66. xiao ming
    124.205.37.*
    链接

    xiao ming 2011-09-08 18:03:07

    问一下老赵,如果类也是未知的,就是根据不同的条件动态加载不同的类,调用不同的方法,用了你的这个试了下效果没有比普通的用法有多少性能的提升,不知您有什么好的做法

  67. 老赵
    admin
    链接

    老赵 2011-09-08 21:23:55

    @xiao ming

    没懂你意思,没有性能提升说明你用的不对。

  68. xiao ming
    124.205.37.*
    链接

    xiao ming 2011-09-13 15:46:43

    public enum ChooseType 
      {
          Bb,
          Cc
      }
    
    public  abstract  class Aa
      {
          public abstract void  Test();
          public abstract void  Test(int i);
          public object ObjectProperty { get; set; }
          public int Int32Property { get; set; }
          public abstract void MethodWithoutArgs();
          public abstract void MethodWithArgs(int a1, string a2);
     }
    public class  Bb
        :Aa
    {
        public override void Test()
        {
            throw new NotImplementedException();
        }
        public override void Test(int i)
        {
            throw new NotImplementedException();
        }
        public override void MethodWithArgs(int a1, string a2)
        {
            throw new NotImplementedException();
        }
        public override void MethodWithoutArgs()
        {
            throw new NotImplementedException();
        }
    
    }
    
    public class Cc
        : Aa
    {
        public override void Test()
        {
            throw new NotImplementedException();
        }
        public override void Test(int i)
        {
            throw new NotImplementedException();
        }
        public override void MethodWithArgs(int a1, string a2)
        {
            throw new NotImplementedException();
        }
        public override void MethodWithoutArgs()
        {
            throw new NotImplementedException();
        }
    
    }
    
    
    
    class Program
    {
        private static Aa _Aa { get; set; }
        static void Main(string[] args)
        {
            int times = 1000000;
            TestOld(times, ChooseType.Bb);
            TestNew(times, ChooseType.Bb);
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    
    
    
    
        static void TestOld(int times,ChooseType ctype)
        {
            var watch = new Stopwatch();
            watch.Start();
            var ctypename = ctype.ToString();
            _Aa = (Aa)Type.GetType("FastReflectionLib.Samples.Benchmarks." + ctypename).
                                    GetConstructor(Type.EmptyTypes).Invoke(null);
            for (var i = 0; i < times; i++)
            {
                var mm = _Aa.ObjectProperty;
            }
    
            watch.Stop();
            Console.WriteLine("old methods" + watch.Elapsed);
        }
        static void TestNew(int times,ChooseType ctype)
        {
            var watch = new Stopwatch();
            watch.Start();
            var ctypename = ctype.ToString();
            var obj = Type.GetType("FastReflectionLib.Samples.Benchmarks." + ctypename).GetConstructor(Type.EmptyTypes).Invoke(null);
            var propertyInfo = obj.GetType().GetProperty("ObjectProperty");
            var accessor = FastReflectionCaches.PropertyAccessorCache.Get(propertyInfo);
            for (int i = 0; i < times; i++)
            {
                var value = accessor.GetValue(obj);
            }
            watch.Stop();
            Console.WriteLine(" Raw Fast Reflection" + watch.Elapsed);
        }
    

    上面的是测试代码,TestOld 要比 TestNew 快一些,但要比 Reflection 方法快不少,这段var obj = Type.GetType("FastReflectionLib.Samples.Benchmarks." + ctypename).GetConstructor(Type.EmptyTypes).Invoke(null); 还有没有优化的地方

  69. 链接

    2011-11-01 10:36:39

    我在调用带有 out ref 参数的方法委托发生异常: System.ArgumentException: 类型为“System.String&”的表达式不能用于方法“System.String PublicReturnWithoutBase_Method(System.String, System.String ByRef)”的类型为“System.String”的参数. 老赵能否补全下!~ 对于表达式树的特殊参数类型我有点摸不着头脑.

  70. tu226
    202.105.32.*
    链接

    tu226 2012-11-01 16:45:24

    今天刚好想用,但是发现不支持带out参数的方法,不知道老赵有没有更新

  71. tester
    111.18.92.*
    链接

    tester 2019-07-12 01:28:56

    有问题,方法定义 void Func(double d1,double d2); 通过类库调用Func(1,2);参数为整型时异常

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我