.NET动态创建对象的小结
来源:互联网 发布:淘宝二手手机回收骗局 编辑:程序博客网 时间:2024/05/05 09:27
.NET动态创建对象的小结
我们新建一个Console控制台项目。然后,添加一个示范类,本文中将通过对这个示范类的操作来进行说明:
public class Calculator { private int x; private int y; public Calculator(){ x = 0; y = 0; } public Calculator(int x, int y) { this.x = x; this.y = y; }}
1.使用无参数构造函数创建对象
上面这个类非常简单,它包含两个构造函数,一个是有参数的构造函数,一个是无参数的构造函数,我们先看看通过反射,使用无参数的构造函数创建对象。创建对象通常有两种方式,一种是使用Assembly的CreateInstance方法:
Assembly asm = Assembly.GetExecutingAssembly(); Object obj = asm.CreateInstance("Reflection4.Calculator", true);// 输出:Calculator() invoked
CreateInstance的第一个参数代表了要创建的类型实例的字符串名称,第二个参数说明是不是大小写无关(Ignore Case)。注意到CreateInstance返回的是一个Object对象,意味着如果想使用这个对象,需要进行一次类型转换。
创建对象的另一种方式是调用Activator类的静态方法CreateInstance:
ObjectHandle handler = Activator.CreateInstance(null, "Reflection4.Calculator");Object obj = handler.Unwrap();
其中CreateInstance的第一个参数说明是程序集的名称,为null时表示当前程序集;第二个参数说明要创建的类型名称。Activator.CreateInstance返回的是一个ObjectHandle对象,必须进行一次Unwrap()才能返回Object类型,进而可以强制转换成我们需要的类型(本例中是Calculator)。ObjectHandle包含在System.Runtime.Remoting命名空间中,可见它是Remoting相关的,实际上ObjectHandle类只是一个对原类型进行了一个包装以便进行封送。
2.使用有参数构造函数创建对象
如果我们想通过有参数的构造函数创建对象,我们可以使用Assembly的CreateInstanc()的重载方法:
// 有参数构造函数创建对象Assembly asm = Assembly.GetExecutingAssembly();Object[] parameters = new Object[2]; // 定义构造函数需要的参数parameters[0] = 3;parameters[1] = 5;Object obj = asm.CreateInstance("Reflection4.Calculator", true, BindingFlags.Default, null, parameters, null, null);// 输出:Calculator(int x, int y) invoked
我们看一下CreateInstance需要提供的参数:
1. BindingFlags,它用于限定对类型成员的搜索。在这里指定Default,意思是不使用BingdingFlags的策略(你可以把它理解成null,但是BindingFlags是值类型,所以不可能为null,必须有一个默认值,而这个Default就是它的默认值);
2. 接下来的参数是Binder,它封装了CreateInstance绑定对象(Calculator)的规则,我们几乎永远都会传递null进去,实际上使用的是预定义的DefaultBinder;
3. 接下来是一个Object[]数组类型,它包含我们传递进去的参数,有参数的构造函数将会使用这些参数;
4. 接下来的参数是一个CultureInfo类型,它包含了关于语言和文化的信息(简单点理解就是什么时候ToString("c")应该显示“¥”,什么时候应该显示“$”)。
动态调用方法
接下来我们看一下如何动态地调用方法。注意,本文讨论的调用不是将上面动态创建好的对象由Object类型转换成Calculator类型再进行方法调用,这和“常规调用”就没有区别了,让我们以.Net Reflection 的方式来进行方法的调用。继续进行之前,我们为Calculator添加两个方法,一个实例方法,一个静态方法:
public int Add(){ int total= 0; total = x + y; Console.WriteLine("Invoke Instance Method: "); Console.WriteLine(String.Format("[Add]: {0} plus {1} equals to {2}", x, y, total)); return total;}public static void Add(int x, int y){ int total = x + y; Console.WriteLine("Invoke Static Method: "); Console.WriteLine(String.Format("[Add]: {0} plus {1} equals to {2}", x, y, total));}
调用方法的方式一般有两种:
1. 在类型的Type对象上调用InvokeMember()方法,传递想要在其上调用方法的对象(也就是刚才动态创建的Calculator类型实例),并指定BindingFlags为InvokeMethod。根据方法签名,可能还需要传递参数。
2. 先通过Type对象的GetMethond()方法,获取想要调用的方法对象,也就是MethodInfo对象,然后在该对象上调用Invoke方法。根据方法签名,可能还需要传递参数。
需要说明的是,使用InvokeMember不限于调用对象的方法,也可以用于获取对象的字段、属性,方式都是类似的,本文只说明最常见的调用方法。
1.使用InvokeMember调用方法
我们先看第一种方法,代码很简单,只需要两行(注意obj在上节已经创建,是Calculator类型的实例):
Type t = typeof(Calculator);int result = (int)t.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj, null);Console.WriteLine(String.Format("The result is {0}", result));输出:Invoke Instance Method:[Add]: 3 plus 5 equals to 8The result is 8
在InvokeMember方法中,第一个参数说明了想要调用的方法名称;第二个参数说明是调用方法(因为InvokeMember的功能非常强大,不光是可以调用方法,还可以获取/设置 属性、字段等。此枚举的详情可参看Part.2或者MSDN);第三个参数是Binder,null说明使用默认的Binder;第四个参数说明是在这个对象上(obj是Calculator类型的实例)进行调用;最后一个参数是数组类型,表示的是方法所接受的参数。
我们在看一下对于静态方法应该如何调用:
Object[] parameters2 = new Object[2];parameters2[0] = 6;parameters2[1] = 9;t.InvokeMember("Add", BindingFlags.InvokeMethod, null, typeof(Calculator), parameters2);输出:Invoke Static Method:[Add]: 6 plus 9 equals to 15
我们和上面对比一下:首先,第四个参数传递的是 typeof(Calculator),不再是一个Calculator实例类型,这很容易理解,因为我们调用的是一个静态方法,它不是基于某个具体的类型实例的,而是基于类型本身;其次,因为我们的静态方法需要提供两个参数,所以我们以数组的形式将这两个参数进行了传递。
2.使用MethodInfo.Invoke调用方法
我们再看下第二种方式,先获得一个MethodInfo实例,然后调用这个实例的Invoke方法,我们看下具体如何做:
Type t = typeof(Calculator);MethodInfo mi = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);mi.Invoke(obj, null);输出:Invoke Instance Method:[Add]: 3 plus 5 equals to 8请按任意键继续. . .
在代码的第二行,我们先使用GetMethod方法获取了一个方法对象MethodInfo,指定BindingFlags为Instance和Public,因为有两个方法都命名为“Add”,所以在这里指定搜索条件是必须的。接着我们使用Invoke()调用了Add方法,第一个参数obj是前面创建的Calculator类型实例,表明在该实例上创建方法;第二个参数为null,说明方法不需要提供参数。
我们再看下如何使用这种方式调用静态方法:
Type t = typeof(Calculator);Object[] parameters2 = new Object[2];parameters2[0] = 6;parameters2[1] = 9;MethodInfo mi = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public);mi.Invoke(null, parameters2);// mi.Invoke(t, parameters2); 也可以这样输出:Invoke Static Method:[Add]: 6 plus 9 equals to 15
可以看到与上面的大同小异,在GetMethod()方法中,我们指定为搜索BindingFlags.Static,而不是BindingFlags.Public,因为我们要调用的是静态的Add方法。在Invoke()方法中,需要注意的是第一个参数,不能在传递Calculator类型实例,而应该传递Calculator的Type类型或者直接传递null。因为静态方法不是属于某个实例的。
NOTE:通过上面的例子可以看出:使用反射可以达到最大程度上的多态,举个例子,你可以在页面上放置一个DropDownList控件,然后指定它的Items的value为你某个类的方法的名称,然后在SelectedIndexChanged事件中,利用value的值来调用类的方法。而在以前,你只能写一些if else 语句,先判断DropDownList返回的值,根据值再决定调用哪个方法。使用这种方式,编译器在代码运行之前(或者说用户选择了某个选项之前)完全不知道哪个方法将被调用,这也就是常说的迟绑定(Late Binding)。
- .NET动态创建对象的小结
- .Net——动态创建对象
- 动态创建类的对象
- 动态创建用户对象对象的方法
- .net中实现运行时从字符串动态创建对象
- .Net基础:学习反射中的动态创建对象
- MFC之对象的动态创建
- java动态代理对象实例的创建
- c++对象的动态创建与释放
- 关于js中动态创建对象的
- 对象的赋值,动态创建属性
- 用.net动态创建类的实例
- .NET动态创建数据表的示例
- 代码动态创建UITableViewCell小结
- 关于JS中如何获取动态加载的对象小结
- 动态创建对象
- 动态创建对象
- 动态创建dom对象
- C++ 扩展和嵌入 Python
- Guacamole-HTML5无客户端远程桌面
- ICS4.0.3创建NuPlayer的处理流程
- ckeditor 3.6.2 详细配置
- 不仅仅是“屠龙之技”-编译器开发者的精神胜利!
- .NET动态创建对象的小结
- 创建数据库
- Android自动更新代码
- Windows环境下用jwplayer+Nginx搭建视频点播服务器
- 汇编指令大全(有注释)
- 构建android 开发环境
- escape,encodeURI,encodeURIComponent函数比较
- MVC框架概述
- 完成端口(IOCP)编程探讨