我发现很多情况我认为我可以使用relfection来解决问题,但我通常不这样做,因为我听到了很多"不使用反射,效率太低"的说法.
现在我处在一个我遇到问题的位置,我找不到任何其他解决方案而不是使用反射new T()
,如本问答中所述.
所以我想知道是否有人可以告诉我反思的具体用途,以及是否有一套指导方针来表明它何时合适以及什么时候不合适?
Mar*_*ell 24
它通常"足够快",如果您需要更快(对于紧密循环等),您可以使用Expression
或ILGenerator
(可能通过DynamicMethod
)进行元编程,以制作极其快速的代码(包括您在C#中无法做的一些技巧).
反射更常用于框架/库场景,其中库按定义对调用者一无所知,并且必须基于配置,属性或模式工作.
Rob*_*Rob 21
如果有一件事我讨厌听到它"不使用反射,那就太低效了".
对于什么来说太低效了?如果您正在编写一个每月运行一次并且不是时间关键的控制台应用程序,那么由于您使用反射,它是否需要30秒而不是28秒才真正重要?
什么时候不适合使用的指南只有你真正可以组合在一起,因为它们严重依赖于你正在做的事情以及效率/效率如何.
Han*_*ant 21
代码效率的一个有用的抽象是将它分为三类时间,每个时间间隔大约3个数量级.
首先是人类时间.当你只需要让一个人对代码的性能感到满意时,你可以做很多事情.人类无法感知需要10毫秒或20毫秒的代码之间的差异,两者都是即时的.当一个程序需要6秒而不是5秒,大约30 亿个机器指令时,人类就会宽容.在人工时运行的程序的常见示例是编译器和点击设计器.使用反射绝不是问题.
然后有I/O时间.当您的程序需要访问磁盘或网络时.I/O很慢,在磁盘的情况下受到机械运动的限制,在网络的情况下是带宽和延迟.您总是可以判断I/O何时是瓶颈,您的程序正在运行,但它并没有大大增加CPU负载.操作系统不断阻塞线程,使其等待I/O请求完成.
反射在I/O时间运行.要检索类型数据,CLR必须读取程序集元数据.如果之前没有这样做,程序将导致页面错误,要求操作系统从磁盘读取数据.接下来的是,粗略地说,反射可以使I/O绑定代码的速度只有两倍.通常更好,因为在第一次性能打击之后,元数据被缓存并且可以更快地检索.因此,反思通常是可接受的权衡.规范示例是序列化和dbase ORM.
然后是机器时间.CPU核心的原始性能是惊人的.属性getter可以在0到1/2 纳秒之间的某个位置执行.这与PropertyInfo.GetValue()相比没有优势.两者都会使CPU保持忙碌,你会看到核心的CPU负载为100%.但GetValue()需要花费数百甚至数千个机器代码指令.不计算在元数据中寻呼所需的时间.虽然没有多少增量时间,但在循环时会快速建立.
如果您无法在人工时间或I/O时间类别中对反射代码进行分类,则反射不太可能是常规代码的合适替代.
保持反射减慢程序速度的关键是不要在循环中使用它.如果要在启动期间从对象读取属性(发生一次),请使用反射.您希望从10,000个未知类型的对象列表中读取属性,使用反射获取属性getter委托一次(搜索项:) PropertyInfo.GetGetMethod
,然后调用委托10,000种类型.StackOverflow上有很多这方面的例子.
我将它用于插件体系结构 - 查看插件文件夹中的程序集,以查找标有自定义属性的方法,该属性指示有关插件的信息 - 以及在日志记录框架中.框架检测程序集本身的自定义属性,该属性包含有关程序集作者,项目,版本信息以及与堆栈跟踪中的所有内容一起记录的其他标记的信息.
要放弃一个"商业秘密",但它是一个好的.框架允许您使用'Story ref'标记每个方法或类,例如
[StoryRef(Ref="ImportCSV1")]
...并且它的想法是它将集成到我们的敏捷项目管理框架中:如果在该类/方法中抛出任何异常,则日志记录方法将使用反射来检查StoryRef
堆栈跟踪中的属性,如果是,那么被记录为该故事的例外.在PM软件中,您可以看到Story的异常(一个故事就像一个极端/敏捷的用例).
我认为这至少是有效的用途!基本上,当它看起来是最简洁,最合适的方式时,我会使用反射.没有其他任何东西可以真正融入其中 - 我无法想象你会使用反射来做出许多效率会产生效果的场合.
归档时间: |
|
查看次数: |
5969 次 |
最近记录: |