• 用反射通过构造函数给窗体传参


    最近在项目上用到反射来调用方法用的比较多,传参包含两种方式,一种是通过变量传参,第二种是通过构造函数传参,下面分别介绍下两种方式:

    先介绍几种获取实例的方法,下面描述中提到的三种方法其实都是大同小异的,核心就是通过System.Reflection.Assembly 类型的CreateInstance方法创建实例。

    //反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间,假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型):
    
    Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL)
    object obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例
    
    //若要反射当前项目中的类可以为:
    Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集
    object obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例,返回为 object 类型,需要强制类型转换
    
    //也可以为:
    Type type = Type.GetType("类的完全限定名");
    object obj = type.Assembly.CreateInstance(type);

    那么简单的解释一下这种方法的原理:

    1.找到要实例化的类所在的程序集,并将之实例为System.Reflection.Assembly 类的对象

    2.利用System.Reflection.Assembly 类提供的CreateInstance方法,创建类的对象

    一、通过变量传参

    通过变量传参稍微简单点,原理很简单,先通过反射获取到类,这里的类需要有个公共变量,然后将该类从object类型强制转换为原本的类名,比如反射调用的DLL中原本类名是Class1,那么通过反射获取创造该类后强制转换为Class1,这样就可以直接通过实例给类中的变量赋值。(注意:如果是调用外部的DLL,需要先引用该类的程序集)

    先创建一个简单类:

    public class Class1
        {
            private string _strId;
            public string ID
            {
                get { return _strId; }
                set { _strId = value; }
            }
            public Class1()
            {
    
            }
    
            public Class1(string str)
            {
                _strId = str;
            }
        }

    然后在主函数中加入代码:

    Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 
    object obj = assembly.CreateInstance("ReflectionTest.Test"); //类的完全限定名(即包括命名空间)
    Class1 entity = obj as Class1;
    entity.ID = "xxxxx";

    调试结果:显示obj对象的确不为空,证明这种方法可行。

    二、通过构造函数传参

    通过构造函数传参稍微复杂,首先修改Class1类,将其构造函数改为:

    public Class1(string str)
    {
         _strId = str;
    }

    假设主函数还是用以前的那样子调用,会直接抛出异常:未找到类型“ReflectionTest.Class1”上的构造函数。这是因为CreateInstance方法默认情况下是通过找无参数的构造函数去创建对象的,现在找不到当然会出错,实时上CreateInstance方法提供了3中签名,其中有CreateInstance(String, Boolean, BindingFlags, Binder, Object [], CultureInfo, Object []) 就可以满足这种情况:

    修改主函数如下:

    Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集
    //object obj = assembly.CreateInstance("ReflectionTest.Class1"); //类的完全限定名(即包括命名空间)
    object[] parameters = new object[1];
    parameters[0] = "test string";
    object obj = assembly.CreateInstance("ReflectionTest.Class1",true,System.Reflection.BindingFlags.Default,null,parameters,null,null);// 创建类的实例

    测试后运行结果正常

    继续加深难度,创建string的对象

    首先知道string是System.String的别名,所以要创建的是System.String的对象,而System.String在mscorlib.dll中,所以需要将mscorlib.dll实例为System.Reflection.Assembly的对象,这里利用System.Type类型的属性Assembly来实现功能。

    System.String的构造函数有很多种,本文中笔者就不墨迹了,采用String( Char []) 。

    最终将主函数中代码改为:

    Type type = Type.GetType("System.String");
    object[] parameters = new object[1];
    char[] lpChar = { 't','e','s','t' };
    parameters[0] = lpChar;
    
    object obj = type.Assembly.CreateInstance("ReflectionTest.Class1",true,System.Reflection.BindingFlags.Default,null,parameters,null,null);// 创建类的实例 

    调试结果:对象为空,失败了,事实上这种方法还有个问题,如将Class1类构造函数修改为

    public Test(string str)
    {
        ID = str;//属性赋值
    }

    调试结果:对象创建成功,但是变量为空

     

    解决方案

    采用System.Activator 类的CreateInstance方法。

    最后见代码:

    Type type = Type.GetType("System.String");
    object[] parameters = new object[1];
    char[] lpCh = { 't', 'e', 's', 't' };
    parameters[0] = lpCh;
    
    object obj = Activator.CreateInstance(type, parameters);

    调试结果:对象创建成功,且变量值正常

    采用System.Activator 类的CreateInstance方法,要比System.Reflection.Assembly的CreateInstance简单有效很多。有兴趣的朋友可以仔细看看。

  • 相关阅读:
    Excel生成二维折线图详细教程 TheChosen
    sql语句截取字段中某一符号前几位的方法? TheChosen
    python快速下载包的镜像源? TheChosen
    Android 超大图长图浏览库 SubsamplingScaleImageView 源码解析
    记录线上APP一个排序比较引发的崩溃 Comparison method violates its general contract!
    Android 内存泄漏检测工具 LeakCanary(Kotlin版)的实现原理
    改数组长度
    枚举数组所有组合
    Ubuntu20.04启动后光标一直闪烁
    harbor镜像仓库清理操作
  • 原文地址:https://www.cnblogs.com/xiangzhong/p/5391721.html
Copyright © 2020-2023  润新知