需求:利用反射实现父模块根据参数动态调用三个子模块。
/// <summary> /// 加载子模块 /// </summary> /// <param name="assemblyName">子模块程序集名称</param> /// <param name="className">要调用的指定函数所在的程序集函数名</param> private void Load(string assemblyName,string className) { string fileDll = string.Format("{0}\\{1}", Path.GetDirectoryName(typeof(Program).Assembly.Location), assemblyName);//typeof的参数是当前类名 if (!File.Exists(fileDll)) { MessageBox.Show("启动失败,系统将退出!"); Application.Exit(); return; } try { Assembly assembly = Assembly.LoadFile(fileDll); Type type = assembly.GetType(className); type.InvokeMember("Run", BindingFlags.InvokeMethod, null, null, null); } catch { MessageBox.Show("启动失败,系统将退出!"); Application.Exit(); } }
反射的缺点:
1.反射会造成编译时无法保证类型安全性。由于反射要严重依赖字符串,所以会丧失编译时的类型安全性。
2.反射速度慢。使用反射时,类型及其成员的名称在编译时未知;要用字符串名称标识每个类型及其成员,以便在运行时发现它们。。也就是说,使用System.Reflection命名空间中的类型扫描程序集的元数据时,反射要不断地执行字符串搜索。通常,字符串搜索执行的是不区分大小写的比较,这会进一步影响速度。
使用反射调用一个成员时,也会对性能产生影响。用反射调用一个方法时,首先必须将实参打包(pack)成一个数组;在内部,反射必须将这些实参解包(unpack)到线程栈上。此外,在调用方法前,CLR必须检查实参具有正确的数据类型。最后,CLR必须确保调用者正确的安全权限来访问被调用的成员。
基于上述原因,最好避免利用反射来访问字段或者调用方法/属性。
如果要写一个应用程序来动态发现和构造类型实例,应采取以下两种技术之一。
1.让类型从一个编译时已知的基类型派生。在运行时,构造派生类型的一个实例,将对它的引用放到基类型的一个变量中(利用转型),再调用基类型定义的虚方法。
2.让类型从一个编译时已知的接口。在运行时,构造类型的一个实例,将对它的引用放到接口类型的一个变量中(利用转型),在调用接口定义的方法。
时间: 2024-10-07 03:53:49