我发现很多情况我认为我可以使用relfection来解决问题,但我通常不这样做,因为我听到了很多“不使用反射,效率太低”的说法。
现在我处于一个我遇到问题的位置,我找不到任何其他解决方案,而不是使用new T()
中的反射,如this question & answer中所述。
所以我想知道是否有人可以告诉我反思的具体用途,以及是否有一套指导方针来说明何时适当以及何时不适用?
答案 0 :(得分:23)
它通常“足够快”,如果您需要更快(对于紧密循环等),您可以使用Expression
或ILGenerator
进行元编程(可能通过DynamicMethod
),使极其快速代码(包括你在C#中无法做到的一些技巧)。
反射更多通常用于框架/库场景,其中库按定义对调用者一无所知,并且必须基于配置,属性或模式工作。
答案 1 :(得分:21)
如果有一件事我<恨> 听到它“不使用反射,那就太低效了。”
效率太低?如果您正在编写一个每月运行一次并且不是时间关键的控制台应用程序,那么是否因为使用反射而需要30秒而不是28秒才真正重要?
不适合使用的指南只有你真正可以放在一起,因为它们严重依赖于你正在做的事情以及效率/效果如何。
答案 2 :(得分:20)
代码效率的一个有用的抽象是将它分为三类时间,每个时间间隔大约3个数量级。
首先是人类时间。当你只需要让一个人对代码的性能感到满意时,你可以做很多事情。人类无法感知需要10毫秒或20毫秒的代码之间的差异,两者都是即时的。当程序需要6秒而不是5秒,大约3 10亿次机器指令时,人类就会宽容。在人工时运行的程序的常见示例是编译器和点击设计器。使用反射绝不是问题。
然后有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时间类别中对反射代码进行分类,则反射不太可能是常规代码的合适替代。
答案 3 :(得分:8)
防止反射减慢程序的关键是不要在循环中使用它。如果要在启动期间从对象读取属性(发生一次),请使用反射。您想要从10,000个未知类型的对象列表中读取属性,使用反射来获取属性getter委托一次(搜索项:PropertyInfo.GetGetMethod
),然后调用委托10,000种类型。 StackOverflow上有很多这方面的例子。
答案 4 :(得分:7)
反思效率不高。它比直接呼叫效率低。因此,当没有等效的编译时安全方法时,我会使用反射。恕我直言,反射的问题不是效率,而是代码的脆弱性,因为它使用的魔法字符串非常重构不友好。
答案 5 :(得分:5)
我将它用于插件体系结构 - 查看插件文件夹中的程序集,以查找标有自定义属性的方法,该属性指示有关插件的信息 - 以及在日志记录框架中。框架检测程序集本身的自定义属性,该属性包含有关程序集作者,项目,版本信息以及与堆栈跟踪中的所有内容一起记录的其他标记的信息。
要放弃'商业秘密',但这是一个好的。框架允许您使用'Story ref'标记每个方法或类,例如
[StoryRef(Ref="ImportCSV1")]
......并且它的想法是它将集成到我们的敏捷项目管理框架中:如果在该类/方法中抛出任何异常,则日志记录方法将使用反射来检查其中的StoryRef
属性。堆栈跟踪,如果是这样,将被记录为该故事的异常。在PM软件中,你可以通过Story看到异常(一个故事就像一个极端/敏捷的用例)。
我认为这至少是有效的用途!基本上,当它看起来只是整洁,以及适当的方式时,我会使用反射。没有其他任何东西可以真正融入其中 - 我无法想象你会使用反射来进行许多调用以提高效率。
答案 6 :(得分:2)
所以我想知道是否有人能说出来 我反思的具体意图 用法,如果有一组 指示何时发布的指导原则 适当的,什么时候不适合?
反射的错误示例是from Wikipedia:
//Without reflection
Foo foo = new Foo();
foo.Hello();
//With reflection
Type t = Type.GetType("FooNamespace.Foo");
object foo = Activator.CreateInstance(t);
t.InvokeMember("Hello", BindingFlags.InvokeMethod, null, foo, null);
在这里,使用反射没有任何好处:使用非反射代码不仅更有效,而且更容易理解。
好的反射的使用是序列化和对象关系映射之类的东西,如果你有一个类的属性列表很容易实现,但是否则需要为每个类定制一个自定义函数