你何时使用反射?模式/反模式

33

我了解c#中的反射API,但我不确定在什么情况下会使用它。使用反射的一些模式和反模式是什么?

17个回答

35

在我正在处理的一个产品中,我们经常使用反射技术,但反射是一个复杂而缓慢的工具。不要仅仅因为听起来有趣或有意思就去寻找使用它的地方。只有当你遇到无法用其他方式解决的问题时才会使用它(例如动态加载插件或框架的程序集、程序集检查、类型在构建时不知道的工厂等)。值得一提的是,浏览反射教程以了解其工作原理是值得的,但不要陷入“手中有锤子,看什么都像钉子”的陷阱中。它具有非常专业化的用途。


28

我在C#中使用反射技术的唯一场合是在工厂模式中,那里我根据配置文件信息创建对象(在我的情况下是网络侦听器)。配置文件提供了程序集的位置、其中类型的名称以及所需的任何其他参数。工厂会获取这些信息并基于此创建侦听器。


11

我不知道这是否是一种模式,但我使用反射从DAO类定义中生成SQL。


1
为什么要重新创建NHibernate?直接使用真正的工具不就行了。 - yfeldblum
8
其中一个原因是我的 DAL 比 NHibernate 更早。我曾考虑过切换,但不想处理 XML 配置混乱的问题。对于我的使用情况来说,我现有的方式更为简洁。但还是感谢您的建议。 - Otávio Décio

10

我在许多地方都使用了反射。主要的广泛类别包括:

  1. 自动生成GUI(即属性编辑器)。您可以循环遍历对象的属性,并使用UI元素工厂的注册表构建表单。我使用属性上的特性来指导UI创建。
  2. 序列化。我编写了使用反射来序列化和反序列化对象的序列化框架。
  3. Web服务。与序列化类似,我使用反射创建和使用SOAP消息,也可生成WSDL。
  4. 特定于领域的语言。解释脚本语言通常会使用反射来绑定对象和方法。
  5. 调试工具。这些工具可以使用反射来检查对象的状态。在故障条件下创建日志消息非常方便。

模式方面,我不确定模式是什么。所有用途之间的共同点是名称引用和后期绑定 - 您希望在运行时绑定到成员。当您动态加载程序集并且不知道需要创建/操作的对象类型时,这通常是最常见的情况。

使用反射具有强大的功能,但它不会使您在聚会上更受欢迎。仅在意向弱的耦合情况下使用它。弱到您希望它在运行时出现故障。 WPF中数据绑定的一个很好的例子。

我不确定反模式,但肯定会涉及在运行时执行应该在编译时执行的操作...


9

没有硬性规定。基本上,如果没有充分的理由,请勿使用反射。 当您无法在没有反射的情况下实现所需功能或者没有反射代码会更长或更难理解时,请使用反射。


6

我发现反射(结合运行时类加载)对于实现插件是必不可少的:

  1. 在已知位置搜索jar / assembly文件
  2. 枚举支持插件接口的类的jar / assembly
  3. 在运行时实例化插件

3

我不打算放弃任何模式,但建议在实际需要时避免使用反射。反射对于跨语言和扩展性情况非常有用,在这些情况下,您无法提前控制对象的类型。


3

我在单元测试中经常使用反射,尤其是当我检查匿名类型时。我还将其用作一种轻松克隆/复制模型对象的方式。与其为每个模型对象编写执行此操作的代码,我可以使用反射轻松创建特定类型的对象,查询传入对象的公共属性并调用克隆对象对应的属性的设置器。我还将其与实现相同方法签名但没有关联接口的设计生成类一起使用。在这些情况下,我可以查询对象以查看它是否具有所需的方法,并在其具有时调用该方法。LINQ2SQL实体也是如此,因此在我的虚拟数据上下文包装器的OnSubmit方法中,我使用反射获取OnValidate方法并在单元测试中调用它。


3

我在二进制序列化器(protobuf-net)中使用它。 我只使用反射来构建模型 - 当它被使用时(即在[反]序列化期间),它使用委托等方式以实现最大的性能。

我还在HyperDescriptor中使用它(连同ComponentModel和Reflection.Emit),以构建加速的属性访问(~100倍于常规反射的速度)。

如果你需要构建自己的Expression,那么出于必要,你需要使用反射。


3

在工厂模式的使用上,+1 -- 在那里非常强大。

除了工厂模式,每次我使用它时,我可能都不应该...

我用它来动态加载实现特定接口的类(我的是来自程序集的菜单项),并在启动时真的后悔了这种用法。我希望我能从配置文件中加载(然后添加一个表单,显示可用的接口以加载)。这很酷,但非常缓慢...

一种反模式是在不知道类设计者为什么将其标记为私有的情况下使用它访问属性。我曾经在 DataGridView WinForms 控件中使用过它来取消布尔变量,以便在移动其补充列时可以移动“伴侣”列。再次说明,这非常酷,但如果新版本更改了该私有属性(它很可能在 3.0 或 3.5 中被删除...),那么该代码将彻底失败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接