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

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

先介绍几种获取实例的方法,下面描述中提到的三种方法其实都是大同小异的,核心就是通过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简单有效很多。有兴趣的朋友可以仔细看看。

时间: 2024-10-22 10:33:21

用反射通过构造函数给窗体传参的相关文章

js构造函数传参

1.直接传参并用this关键字初始化属性 function Person(name,age,learn){ this.name = name; this.age = age; this.learn = learn || false; } Person.prototype.isWork=false; Person.prototype.work=function(){ this.isWork=true; }; Person.prototype.unwork = function(){ this.is

MvvmCross for WPF 支持子窗体显示、关闭、传参

最近在做 PCL(Portable Class Library)平台的项目,所以发一下自己遇到的问题 MvvmCross 是 PCL 平台的一个 MVVM 框架 地址:https://github.com/MvvmCross/MvvmCross 支持的平台: Silverlight for WP7, WP8 Mono for Android (or Xamarin.Android) MonoTouch for iOS (or Xamarin.iOS) the WinRT XAML framewo

dynamic结合匿名类型 匿名对象传参

首先说明下,我一般很少用dynamic关键字(类)的,因为毕竟是由反射实现的,所以对于性能方面还是吃亏不少(注:由于心里没底,查了一些资料得知,dynamic实质上好像不是由反射实现的,其性能也比直接反射要高不少,至于为什么,我也不明白,希望你们知道的能留言告诉我一下!谢谢啦 ^_^)我也不知道为什么DLR能够实现与反射一样的实现,但代码,性能要比后者简介,高效!! 我这里就纯粹在这里坐下记录 匿名对象(类型)传参的几种方式 代码如下: class Program { static void M

c++代码赏析之类对象传参

#include <iostream> using namespace std; class A { private: int x; public: A():x(0) { x = 0; cout << "construct" << endl; } A(const A &a) { x = a.x; cout << "construct copy" << endl; } ~A(){ cout <&

[Autofac] 给Resolve传参

1 //传参 2 var frm = Container.Resolve<SettlementCheckTradeEditFrm>(new NamedParameter("settlement", Settlement)); 3 frm.ShowDialog(); 4 Settlement.UserTrade.UserID = frm.UserID; 5 6 //SettlementCheckTradeEditFrm增加新的构造函数 7 public SettlementC

组合模式解决原型创建对象传参和共享难题

//组合构造函数+原型模式 function Box(name,age){ //保持独立的用构造函数 this.name = name; this.age = age; this.family = ['哥哥','姐姐','妹妹'] }; Box.prototype = { //保持共享的用原型 constructor:Box, run:function(){ return this.name + this.age + '运行中...'; } }; var box1 = new Box('Lee'

地址栏传参不安全的解决方案

地址栏传递参数,比如    ?uid=45   那么,用户就可以修改45位其他值,就会获取到其他的信息.很不安全: 解决方案方法:    可逆加密 + GUID + cookie 单纯的加密,比如  要传45这个参数,加密成了  abcd(假如),但是人家只要看到abcd,那个之后别人想看45的信息,输入abcd参数即可.还是有安全隐患: 可行方案浏览器在需要的地方(或者登陆的时候就行),生成一个全球唯一标示GUID,之后存在 cookie里面.那么在需要传递参数的地方,把这个GUID从cook

使用java传参调用exe并且获取程序进度和返回结果的一种方法

文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在某个项目中需要考虑使用java后台调用由C#编写的切图程序(exe),并且前端能够获取到切图的进度和相关描述信息. 2.解决思路 a.首先改造切图程序为接受参数从Main函数传递. b.编写java后台传参调用exe的函数. c.解决通信问题. 3.具体实现 3.1改写C#窗体程序 C#中的入口程序为Main函数,其中Main函数默认是没有参数的,如果添加参

枚举|标志枚举+|(或)和&amp;(与)运算|类型转换|值类型和引用类型|传参|异常|垃圾回收

枚举部分 enum 关键字用于声明枚举,即一种由一组称为枚举数列表的命名常量组成的独特类型. 通常情况下,最好是在命名空间内直接定义枚举,以便该命名空间中的所有类都能够同样方便地访问它. 但是,还可以将枚举嵌套在类或结构中.默认情况下,第一个枚举数的值为 0,后面每个枚举数的值依次递增 1. 例1: //此枚举的默认值是从0开始 enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; 例2: //此枚举的默认值是从1开始,下标为3的tue值为7,从下标3开始