1
90
反射最常用于绕过静态类型系统,但是它也有一些有趣的用例: 让我们写一个ORM! 如果您熟悉nhibernate或大多数其他表单,您可以编写映射到数据库中表的类,如下所示:
你觉得
它的 完全地 可以以类型安全的方式拥有相同的功能,只需要求用户重写一个方法,将字段复制到数据行对象中,但这将导致大量样板代码和膨胀。 树桩! Rhino Mocks 是一个模拟框架。您将一个接口类型传递给一个方法,在后台,框架将动态地构造和实例化一个实现接口的模拟对象。 当然,程序员可以手工编写模拟对象的样板代码,但是如果框架为她做这件事,她为什么要这样做呢? 元数据! 我们可以用属性(元数据)来修饰方法,这些属性(元数据)可以用于多种用途:
您需要对方法进行反射以检查属性。大多数 AOP frameworks for .NET 使用属性进行策略注入。 当然,您可以在内联中编写相同类型的代码,但是这种样式更具声明性。 让我们建立一个依赖框架! 许多IOC容器需要一定程度的反射才能正常运行。例如:
我们的IOC容器将实例化一个文件验证器,并将ILogger的适当实现传递给构造函数。哪些实施?这取决于它是如何实现的。 假设我在配置文件中给出了程序集和类的名称。语言需要将类的名称作为字符串读取,并使用反射来实例化它。 除非我们在编译时知道实现,否则没有基于类名称实例化类的类型安全方法。 后期装订/鸭子打字 您希望在运行时读取对象属性的原因有很多种。我选择日志记录作为最简单的用例——假设您正在编写一个日志记录程序,它接受任何对象并将其所有属性吐出到一个文件中。
你 能够 为所有可能的静态类型重写Log方法,或者只使用反射来读取属性。 一些语言,如ocaml和scala支持静态检查的duck类型(称为 structural typing ,但有时您只是没有对象接口的编译时知识。 或者正如Java程序员所知道的,有时类型系统会得到你的方式,并要求你编写各种样板代码。有一篇著名的文章描述了有多少种设计模式 simplified with dynamic typing . 有时,绕过类型系统可以让您将代码重构得比静态类型更深入,从而使代码更干净(最好隐藏在程序员友好的API之后)。许多现代静态语言都采用了“可能的静态类型,必要的动态类型”的黄金法则,允许用户在静态代码和动态代码之间切换。 |
2
11
项目,例如 hibernate (O/R映射)和 StructureMap (依赖注入)没有反射是不可能的。如何单独使用多态性来解决这些问题? 使这些问题如此难以解决的是图书馆 直接地 了解关于类层次结构的任何信息—它们不知道。但是它们需要了解类的结构,以便(例如)仅使用字段名和属性名将数据库中的任意数据行映射到类中的属性。 反射对 映射 问题。理念 convention over code 变得越来越流行,你需要某种类型的思考来做到这一点。 在.NET 3.5+中,您有一种选择,即使用表达式树。这些都是强类型的,并且使用lambda和表达式树(参见 Fluent NHibernate , Ninject )但请记住,并不是每种语言都支持这些类型的构造;当它们不可用时,您基本上会陷入反射。 在某种程度上(我希望我不会对此感到恼火),反射经常被用作面向对象语言中的解决方法/黑客,用于功能语言中免费提供的功能。随着功能语言越来越流行,和/或更多的OO语言开始实现更多的功能特性(如C),我们很可能会看到反射越来越少地被使用。但我怀疑它仍然存在,对于更传统的应用程序,比如插件(正如其他响应者之一乐于指出的那样)。 |
3
8
事实上, 你每天都在使用反光系统 :您的计算机。 当然,它没有类、方法和对象,而是有程序和文件。程序创建和修改文件就像方法创建和修改对象一样。但是程序 是 文件本身,一些程序甚至检查或创建 其他程序! 那么,为什么Linux的安装是自反的,以至于没有人会考虑它,对OO程序来说是可怕的呢? |
4
6
我见过自定义属性的良好用法。例如数据库框架。
然后可以使用反射来获得关于这些字段的进一步信息。我很确定Linq to SQL做了类似的事情… 其他示例包括测试框架…
|
5
6
没有反省,你经常要重复很多。 考虑以下情况:
通常不能在C/C++中做这些事情,而不重复代码中其他地方的受影响的方法和属性的整个列表。 事实上,C/C++程序员经常使用 Interface description language 在运行时公开接口(提供反射形式)。 明智地将反射和注释与定义良好的编码约定结合使用,可以避免代码重复,提高可维护性。 |
6
3
我认为反射是这些机制中的一种,它很强大,但很容易被滥用。为达到特定的目的,你被赋予了成为“超级用户”的工具,但这并不意味着取代正确的面向对象设计(就像面向对象设计不是解决所有问题的解决方案一样),也不意味着被轻率地使用。 由于Java的结构方式,在运行时,您已经付出了在内存中代表类层次结构的代价(与C++相比,除非使用虚拟方法之类的东西,否则不需要付出任何代价)。因此,完全阻止它是没有成本依据的。 反射对于序列化之类的事情很有用——Hibernate或Digester之类的事情可以使用反射来确定如何自动地最佳地存储对象。类似地,JavaBeans模型基于方法的名称(我承认这是一个可疑的决定),但是您需要能够检查哪些属性可用于构建可视化编辑器之类的东西。在Java的最新版本中,反射是使注释有用的工具。您可以使用源代码中存在的这些实体编写工具并进行元编程,但可以在运行时访问这些实体。 作为Java程序员,有可能经历整个职业生涯,而不必使用反射,因为你处理的问题不需要它。另一方面,对于某些问题,这是非常必要的。 |
7
3
如上所述,反射主要用于实现需要处理任意对象的代码。例如,ORM映射器需要从用户定义的类中实例化对象,并用数据库行中的值填充它们。实现这一点的最简单方法是通过反射。 实际上,你是对的,反思是 经常 代码气味。大多数时候,你在课堂上工作,不需要思考——如果你知道你的类型,你可能会牺牲类型的安全性、性能、可读性以及在这个世界上所有的好东西,这是不必要的。但是,如果您正在编写库、框架或通用实用程序,则可能会遇到使用反射进行最佳处理的情况。 这是在Java中,这是我所熟悉的。其他语言提供的东西可以用来实现相同的目标,但在爪哇,反射有明确的应用,这是最好的(有时也是唯一)的解决方案。 |
8
3
单元测试软件和框架(如nunit)使用反射获取要执行和执行的测试列表。它们在一个模块/程序集/二进制文件中找到所有测试套件(在C中,这些套件由类表示)和这些套件中的所有测试(在C中,这些是类中的方法)。nunit还允许您标记一个带有预期异常的测试,以防您正在测试异常合同。 如果没有反射,您需要以某种方式指定哪些测试套件可用,以及每个套件中哪些测试可用。此外,像异常这样的事情需要手动测试。我见过的C++单元测试框架使用宏来实现这一点,但是有些东西仍然是手工的,这种设计是有限制性的。 |
9
3
保罗·格雷厄姆有一个 great essay 这也许是最好的说法:
结束语。…
|
10
2
一切都是为了快速发展。
|
11
2
插件就是一个很好的例子。 工具是另一个示例-检查器工具、构建工具等。 |
12
2
我将举一个例子,说明在我开始学习时给出的C解决方案。 它包含用[exercise]属性标记的类,每个类包含未实现的方法(引发NotImplementedException)。该解决方案还进行了单元测试,但都失败了。 目标是实现所有方法并通过所有单元测试。 该解决方案还具有一个用户界面,它可以读取所有标有excercise的类,并使用反射来生成用户界面。 后来我们被要求实现我们自己的方法,后来我们仍然理解用户界面是如何“神奇地”被更改为包含我们实现的所有新方法的。 非常有用,但往往不被很好地理解。 |
13
2
其背后的想法是能够查询任何图形用户界面对象属性,并在图形用户界面中提供这些属性以进行定制和预配置。目前,它的应用已经得到了扩展,证明是可行的。 编辑:拼写 |
14
1
它对于依赖注入非常有用。您可以探索使用给定属性实现给定接口的已加载程序集类型。结合正确的配置文件,它被证明是在不修改客户机代码的情况下添加新继承类的一种非常强大和干净的方法。
另外,如果您所做的编辑器并不真正关心底层模型,而是关注对象的直接结构,那么ala
|
15
1
没有反射,任何插件架构都无法工作! |
16
1
python中非常简单的例子。假设有一个类有三个方法:
现在,在其他一些类中,您希望用一些额外的行为来修饰这些方法(也就是说,您希望该类模仿某个类,但具有额外的功能)。 这很简单:
|
17
1
通过反射,您可以编写少量不需要经常更改的独立于域的代码,而不是编写更多需要更频繁更改的依赖域的代码(例如添加/删除属性时)。使用项目中已建立的约定,您可以基于某些属性、属性等的存在来执行公共函数。不同域之间对象的数据转换就是一个例子,其中反射非常有用。 或者域中的一个更简单的示例,在该示例中,您希望在属性更改时将数据从数据库转换为数据对象,而不需要修改转换代码,只要保持约定(在本例中,匹配属性名和特定属性):
|
18
1
还没有提到的一个用法:虽然反射通常被认为是“慢的”,但是可以使用反射来提高使用类似接口的代码的效率
|
JBryanB · 如何从基本抽象类访问类属性 1 年前 |
Gabe Tucker · 无法在golang中分配接口对象指针 2 年前 |
jkone27 · F#-在编译时从字符串生成简单的空类型 6 年前 |
John Bustos · C#通用工厂模式,不说明通用工厂模式的类型 6 年前 |
Randall Flagg · 访问propertyinfo中的属性 6 年前 |
Kacper · 在反映的全名和成员c后的“*”中,“+”是什么意思# 6 年前 |
tobeypeters · 反射铸造 6 年前 |
myst02 · 如何在另一个方法之后调用该方法? 6 年前 |