它说大多数高级动态类型语言都是自反的。维基百科上的反射(计算机编程)解释说,但它并没有真正清楚地说明它的含义。任何人都可以通过相关示例以更简单的方式解释它吗?
5 回答
举个例子,如何以实际的方式使用反射:
假设您正在开发一个您想使用插件扩展的应用程序。这些插件是简单的程序集,只包含一个名为 Person 的类:
namespace MyObjects
{
public class Person
{
public Person() { ... Logic setting pre and postname ... }
private string _prename;
private string _postname;
public string GetName() { ... concat variabes and return ... }
}
}
好吧,插件应该在运行时扩展您的应用程序。这意味着,当您的应用程序已经运行时,应该从另一个程序集中加载内容和逻辑。这意味着这些资源不会编译到您的程序集中,即 MyApplication.exe。假设它们位于库中:MyObjects.Person.dll。
您现在面临这样一个事实,即您需要提取此信息,例如从 MyObjects.Person 访问 GetName() 函数。
// Create an assembly object to load our classes
Assembly testAssembly = Assembly.LoadFile(Application.StartUpPath + @"MyObjects.Person.dll");
Type objType = testAssembly.GetType("MyObjects.Person");
// Create an instace of MyObjects.Person
var instance = Activator.CreateInstance(objType);
// Call the method
string fullname = (string)calcType.InvokeMember("GetName",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
null, instance, null);
如您所见,您可以使用 System.Reflection 在运行时动态加载资源。这可能有助于理解您可以使用它的方式。
查看此页面以查看如何更详细地访问程序集的示例。和我写的内容基本一样。
为了更好地理解反射,请考虑评估程序的解释器。解释器是一个评估其他程序的程序。
该程序可以(1)检查和(2)修改其(a)自己的状态/行为,或运行它的干预者的状态/行为(b)。
然后有四种组合。以下是每种操作的示例:
- 1a -- 读取对象具有的字段列表
- 2a -- 根据字段名称修改一个字段的值;方法的反射调用。
- 1b -- 检查当前堆栈以了解当前执行的方法是什么
- 2b -- 修改堆栈或语言中某些操作的执行方式(例如消息发送)。
a 型称为结构反射。b型称为行为反射。类型 a 的反射在语言中很容易实现。b 类型的反射要复杂得多,尤其是 2b——这是一个开放的研究课题。大多数人通过反思理解的是1a和2a。
理解具体化的概念以理解反射是很重要的。当解释程序中的语句被评估时,解释器需要表示它。解释器可能具有对要解释的程序的字段、方法等进行建模的对象。毕竟,解释器也是一个程序。通过反射,解释程序可以获得对解释器中表示其自身结构的对象的引用。这是物化。(下一步是了解因果关系)
反射特征有很多种,有时很难理解什么是反射,什么不是反射,以及它的含义。从程序和解释器的角度思考。我希望它能帮助您理解维基百科页面(可以改进)。
反射是查询您在运行时编写的程序的元数据的能力,例如:在程序集中找到哪些类,这些类包含哪些方法、字段和属性等等。
.net 甚至包含“属性”,这些是您可以用它们装饰的类、方法、字段等,它们的所有目的都是添加您可以在运行时查询的自定义元数据。
很多时候细节仅取决于元数据。在验证时,我们不关心 string 或 int,但我们关心它不应该为 null。因此,在这种情况下,您需要在不关心特定类的情况下检查属性或属性。图片中有反射。同样,如果您喜欢动态生成方法(在 C# 4.0 的动态对象中可用),也可以使用反射。基本上,它有助于进行行为驱动或面向方面的编程。
另一个流行的用途是测试框架。他们使用反射来寻找在代理环境中测试和运行它的方法。
这是编程语言根据运行时信息调整其行为的能力。在 .Net/C# 世界中,这经常被使用。例如,当将数据序列化为 xml 时,可以添加一个属性来指定生成的 xml 中的字段名称。
对于programmers.stackexchange.com 来说,这可能是一个更好的问题。
但这基本上只是意味着您可以从代码中查看代码。
在我 VB6 的日子里,有一些 UI 对象有一个 Text 属性,而其他一些 UI 对象有一个 Description(或者除了“Text”之外的东西,我忘记了)。这很痛苦,因为我无法封装代码来以相同的方式处理这两种对象。通过反射,我至少能够查看对象是否具有 Text 或 Description 属性。
或者有时对象可能都具有 Text 属性,但它们派生自不同的基类并且没有应用任何接口。同样,如果没有反射的帮助,很难将这样的代码封装在静态类型语言中,但是通过反射,即使是静态类型语言也可以处理它。