所以我试着搜索,希望有人对此有一个很好的解释,没有运气.
我问了我的另一个朋友一个不同的问题(我现在已经忘记了),他的回答只是在他签字之前的"反思".
我仍然是C#世界的新手,曾经是业余的VB.net程序员(也是JavaScript,ActionScript和C),我正在尽我所能去掌握这些先进的概念.
有许多哲学答案 - "应用程序在看自己" - 但它们没有提供任何实际的提示,说明实际发生的事情或在该环境中如何使用它.
那么,什么是反思,为什么重要,以及为什么/如何使用它?
Reflection提供了在运行时确定事物和执行代码的能力.
你不具备使用它,如果你不想,但它是动态行为非常方便.
例如:
a)您可以使用反射来配置应用程序,方法是加载外部配置文件并根据它启动服务.您的应用程序不必事先知道实现这些服务的类,只要它们符合特定的接口或API即可.
b)使用反射,您可以动态生成类和代码,这简化了某些编程任务,因为程序员不必显式创建所有需要的代码.
c)对于通过检查代码工作的程序来说,反思也是非常宝贵的.一个例子是IDE或UI设计师.
d)反射可以帮助您减少样板代码.
e)反射在您的代码中定义迷你域特定语言(DSL)很方便.
(我的定义)反射是能够编写在运行时执行代码的静态代码,通常在编译时确定.
例如,我可以通过编译该命令来调用类方法来绘制,例如:
pen.DrawLine()
或者通过反射,我可以先看看我的对象是否有一个名为"drawline"的方法,如果有,请调用它.(注意这不是实际的C#Reflection语法)
if(pen.Methods.Contains("DrawLine")) { pen.InvokeMethod("DrawLine")) }
我不是反射大师,但我使用反射作为插件架构.
通过反射,我可以在运行时加载.NET程序集(在本例中为dll),找出.NET程序集中的所有类型,查看是否有任何类型实现特定的接口,如果是,则实例化class,我调用接口方法.
我知道用例有点技术性,但本质上反射允许我动态加载插件(即在运行时),并允许我对它进行类型安全的调用.
反射最常见的用途是以前称为RTTI(运行时类型信息)的扩展,主要是C++程序员的领域.
反射是.net构建方式的副作用,Microsoft选择将其用于创建Visual Studio的库和.net运行时公开给Microsoft以外的开发人员.
大多数反射库都侧重于可以在运行时调用的类型发现和创建.这允许一些非常强大的自引用代码.以下示例位于我们的配置管理系统的核心(为清晰起见,删除了一些位):
public static IMyCompanySetting UnwrapSetting(XmlNode settingNode) { string typeName = settingNode.Attributes["type"].Value; string typeAssembly; if(settingNode.Attributes["assembly"] != null) { typeAssembly = settingNode.Attributes["assembly"].Value; } Type settingType = null; Assembly settingAssembly = null; try { // Create an object based on the type and assembly properties stored in the XML try { settingAssembly = Assembly.Load(typeAssembly); if (settingAssembly == null) { return null; } } catch (Exception outerEx) { try { settingType = GetOrphanType(typeName); } catch (Exception innerEx) { throw new Exception("Failed to create object " + typeName + " :: " + innerEx.ToString(), outerEx); } } // We will try in order: // 1. Get the type from the named assembly. // 2. Get the type using its fully-qualified name. // 3. Do a deep search for the most basic name of the class. if (settingType == null && settingAssembly != null) settingType = settingAssembly.GetType(typeName); if (settingType == null) settingType = Type.GetType(typeName); if (settingType == null) settingType = GetOrphanType(typeName); if (settingType == null) throw new System.Exception( String.Format("Unable to load definition for type {0} using loosest possible binding.", typeName)); } catch (Exception ex) { throw new CometConfigurationException( String.Format("Could not create object of type {0} from assembly {1}", typeName, typeAssembly), ex); } bool settingIsCreated = false; IMyCompanySetting theSetting = null; // If the class has a constructor that accepts a single parameter that is an XML node, // call that constructor. foreach (ConstructorInfo ctor in settingType.GetConstructors()) { ParameterInfo[] parameters = ctor.GetParameters(); if (parameters.Length == 1) { if (parameters[0].ParameterType == typeof(XmlNode)) { object[] theParams = { settingNode }; try { theSetting = (IMyCompanySetting)ctor.Invoke(theParams); settingIsCreated = true; } catch (System.Exception ex) { // If there is a pre-existing constructor that accepts an XML node // with a different schema from the one provided here, it will fail // and we'll go to the default constructor. UtilitiesAndConstants.ReportExceptionToCommonLog(ex); settingIsCreated = false; } } } }
这段代码允许我们创建无限数量的类来实现IMyCompanySetting,并使用XML对它们进行序列化和反序列化.然后,给定一块XML作为对象序列化的输出,系统可以将其转换回对象,即使对象本身来自序列化库没有静态链接的库.
如果没有它,有三件事反映在这里是不可能的:
在运行时根据其名称加载程序集.
在运行时根据其名称从程序集加载对象.
根据编译时未知的类对象的签名调用对象构造函数.