前言
废话不多说,“反射” 有哪些用途呢?根据我目前接触到的,总结了下面 3 种常见的反射应用场景:
1,动态加载对象。 2,赋予应用程序装载插件的能力。 3,创建对象并给对象属性赋值。
下面按照顺序,举例说明这 3 种反射场景。
一,动态加载对象
这里以动态加载应用程序窗体为例。假如有个按钮,用户点击按钮后,弹出其他窗体,常规代码如下:
using System; using System.Windows.Forms; namespace Reflect_Test { public partial class Form1 : Form { public Form1() { InitializeComponent(); } //点击按钮,Form2 弹出 private void button1_Click(object sender, EventArgs e) { Form2 form2 = new Form2(); form2.Show(); } } }
如果有个需求,按下按钮,弹出 Form3,而不是 Form3,怎么办。最最直接的办法就是把代码改一下,Form2 改成 Form3 就行了。这样是可以,但是你不得重新编译代码然后发布啊,万一哪天客户改变主意了,说还是 Form2 好看好用,要改回 Form2 ,怎么办,再改代码吗重新编译发布?会被折腾死吧。
进阶方案,弄一个 ini 配置文件,做一个配置,这样就不用修改代码了,代码如下:
public partial class Form1 : Form { //配置管理器 IniManagement iniManagement = new IniManagement(); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form form = new Form(); string selectedForm = iniManagement.IniReadValue("Form", "SelectedForm"); switch (selectedForm) { case "Form2": form = new Form2(); break; case "Form3": form = new Form3(); break; /*Other case...*/ default: ; break; } form.Show(); } }
这样一来只需要修改下配置文件,就能实现窗体切换。那么问题来了,如果客户财大气粗,往桌子上拍了一沓软妹币,说,再做个 Form4 看看效果呢。gg,只能增加一个 case,这段代码又要改了,我们的 switch 只能用来对付已知的可能。
这个时候,就要抛弃 switch,使用反射,做个可配置化的升级版,代码如下:
public partial class Form1 : Form { //配置管理器 IniManagement iniManagement = new IniManagement(); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form form = new Form(); //读取配置文件 //string formConfig = iniManagement.IniReadValue("Form", "SelectedForm"); //为了便于观察,这里直接写出配置文件的配置 string formConfig = @"D:\Reflect Test\Form4\bin\Debug\Form4.dll,Form4.Form4"; string[] dllClassPair = formConfig.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); form = ReflectTools.CreateInstance(dllClassPair[0], dllClassPair[1]) as Form; form.Show(); } } public static class ReflectTools { public static Object CreateInstance(string appPathName, string className) { //Form4 的 dll 的位置 if (!File.Exists(appPathName)) return null; //加载dll Assembly assembly = Assembly.LoadFrom(appPathName); if (assembly == null) return null; try { //反射出窗体对象 //className: 程序集.类 return assembly.CreateInstance(className); } catch { return null; } } }
这样,我们就可以把编写好的 Form4.dll,丢在指定的目录里,再配置下配置文件就可以了。代码会从 dll 里反射出 Form4. 以后再来什么Form5、Form6、XXX,这段代码都是不用动的。其他需要动态加载的对象都可以通过这样的方式进行。
二、赋予应用程序装载插件的能力