利用Type.InvokeMember调用指定函数

需求:利用反射实现父模块根据参数动态调用三个子模块。

        /// <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.让类型从一个编译时已知的接口。在运行时,构造类型的一个实例,将对它的引用放到接口类型的一个变量中(利用转型),在调用接口定义的方法。

posted on 2014-09-16 14:49  明树  阅读(1595)  评论(0编辑  收藏  举报