4、如何使用反射获取类型
首先我们来看如何获得类型信息。
获得类型信息有两种方法,一种是得到实例对象
这个时侯我仅仅是得到这个实例对象,得到的方式也许是一个object的引用,也许是一个接口的引用,但是我并不知道它的确切类型,我需要了解,那么就可以通过调用System.Object上声明的方法GetType来获取实例对象的类型对象,比如在某个方法内,我需要判断传递进来的参数是否实现了某个接口,如果实现了,则调用该接口的一个方法:
…
public void Process( object processObj )
{
Type t = processsObj.GetType();
if( t.GetInterface(“ITest”) !=null )
…
}
…
另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:
Type t = Type.GetType(“System.String”);
需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件,或者在已经获得的Assembly实例上面调用GetType。
本装配件中类型可以只写类型名称,另一个例外是mscorlib.dll,这个装配件中声明的类型也可以省略装配件名称(.Net装配件编译的时候,默认都引用了mscorlib.dll,除非在编译的时候明确指定不引用它),比如:
System.String是在mscorlib.dll中声明的,上面的Type t = Type.GetType(“System.String”)是正确的
System.Data.DataTable是在System.Data.dll中声明的,那么:
Type.GetType(“System.Data.DataTable”)就只能得到空引用。
必须:
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
这样才可以,大家可以看下面这个帖子:
http://expert.csdn.net/Expert/topic/2210/2210762.xml?temp=.1919977
qqchen的回答很精彩
5、如何根据类型来动态创建对象
System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");DataTable table = (DataTable)Activator.CreateInstance(t); 例二:根据有参数的构造器创建对象
namespace TestSpace {
public class TestClass
{
private string _value;
public TestClass(string value) {
_value=value;
}
}
}
…
Type t = Type.GetType(“TestSpace.TestClass”);
Object[] constructParms = new object[] {“hello”}; //构造器参数
TestClass obj = (TestClass)Activator.CreateInstance(t,constructParms);
…
把参数按照顺序放入一个Object数组中即可
首先我们来看如何获得类型信息。
获得类型信息有两种方法,一种是得到实例对象
这个时侯我仅仅是得到这个实例对象,得到的方式也许是一个object的引用,也许是一个接口的引用,但是我并不知道它的确切类型,我需要了解,那么就可以通过调用System.Object上声明的方法GetType来获取实例对象的类型对象,比如在某个方法内,我需要判断传递进来的参数是否实现了某个接口,如果实现了,则调用该接口的一个方法:
…
public void Process( object processObj )
{
Type t = processsObj.GetType();
if( t.GetInterface(“ITest”) !=null )
…
}
…
另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:
Type t = Type.GetType(“System.String”);
需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件,或者在已经获得的Assembly实例上面调用GetType。
本装配件中类型可以只写类型名称,另一个例外是mscorlib.dll,这个装配件中声明的类型也可以省略装配件名称(.Net装配件编译的时候,默认都引用了mscorlib.dll,除非在编译的时候明确指定不引用它),比如:
System.String是在mscorlib.dll中声明的,上面的Type t = Type.GetType(“System.String”)是正确的
System.Data.DataTable是在System.Data.dll中声明的,那么:
Type.GetType(“System.Data.DataTable”)就只能得到空引用。
必须:
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
这样才可以,大家可以看下面这个帖子:
http://expert.csdn.net/Expert/topic/2210/2210762.xml?temp=.1919977
qqchen的回答很精彩
5、如何根据类型来动态创建对象
System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");DataTable table = (DataTable)Activator.CreateInstance(t); 例二:根据有参数的构造器创建对象
namespace TestSpace {
public class TestClass
{
private string _value;
public TestClass(string value) {
_value=value;
}
}
}
…
Type t = Type.GetType(“TestSpace.TestClass”);
Object[] constructParms = new object[] {“hello”}; //构造器参数
TestClass obj = (TestClass)Activator.CreateInstance(t,constructParms);
…
把参数按照顺序放入一个Object数组中即可
解决方案 »
- foreach循环输出数组的问题
- C#中如何调用.OCX中的函数?
- p2p文件传输
- 关于字段命名,内存资源效率问题,高人进呀 谢谢~~~~
- WinForm程序如何实现皮肤更换?
- 通过ImageButton Calendar TextBox做一个自定义控件(高手请教)
- 三目运算,怎么写的?
- ==分不多了,谢谢==Socket传输时怎么区分文件和文本=====
- B/S程序生成Excel时经常出现“无法找到网页”错误,将服务器Win2000Server重新启动后正常
- 请问.NET技术 C#有离线游览器吗?就是做成chm格式,下载后当帮助使用,有的话,请告知下载地址
- 在ASP.NET应用程序里,大量用DataGrid的缺点在哪里?
- 如何通过编程的方式更改IE的proxy设置?
namespace TestSpace
{
public class TestClass {
private string _value;
public TestClass() {
}
public TestClass(string value) {
_value = value;
} public string GetValue( string prefix ) {
if( _value==null )
return "NULL";
else
return prefix+" : "+_value;
} public string Value {
set {
_value=value;
}
get {
if( _value==null )
return "NULL";
else
return _value;
}
}
}
} 上面是一个简单的类,包含一个有参数的构造器,一个GetValue的方法,一个Value属性,我们可以通过方法的名称来得到方法并且调用之,如://获取类型信息
Type t = Type.GetType("TestSpace.TestClass");
//构造器的参数
object[] constuctParms = new object[]{"timmy"};
//根据类型创建对象
object dObj = Activator.CreateInstance(t,constuctParms);
//获取方法的信息
MethodInfo method = t.GetMethod("GetValue");
//调用方法的一些标志位,这里的含义是Public并且是实例方法,这也是默认的值
BindingFlags flag = BindingFlags.Public | BindingFlags.Instance;
//GetValue方法的参数
object[] parameters = new object[]{"Hello"};
//调用方法,用一个object接收返回值
object returnValue = method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null); 属性与方法的调用大同小异,大家也可以参考MSDN7、动态创建委托
委托是C#中实现事件的基础,有时候不可避免的要动态的创建委托,实际上委托也是一种类型:System.Delegate,所有的委托都是从这个类派生的
System.Delegate提供了一些静态方法来动态创建一个委托,比如一个委托:namespace TestSpace {
delegate string TestDelegate(string value);
public class TestClass {
public TestClass() {
}
public void GetValue(string value) {
return value;
}
}
}
使用示例:
TestClass obj = new TestClass();
//获取类型,实际上这里也可以直接用typeof来获取类型
Type t = Type.GetType(“TestSpace.TestClass”);
//创建代理,传入类型、创建代理的对象以及方法名称
TestDelegate method = (TestDelegate)Delegate.CreateDelegate(t,obj,”GetValue”);String returnValue = method(“hello”); 到这里,我们简单的讲述了反射的作用以及一些基本的用法,还有很多方面没有涉及到,有兴趣的朋友可以参考MSDN。
很奇怪,很多人都不愿看MSDN,其实你想要的答案,99%都可以在里面找到。
推荐
不知道你是怎么理解非托管资源的你所说的Remoting、WinForm、Data这几个命名空间的类都是处在托管范围内的土生土长的.Net的类,最多也就是某些类使用了一些非托管资源非托管资源,需要元数据,才能在托管环境下使用,因为反射需要元数据,不管是使用自动导入Com类型库,还是在程序中定义Com类型,实际上在运行期都可以获得非托管资源在托管环境下的元数据,所以,从这个意义上来说,对于非托管资源和托管资源的使用,实际上是没有区别的
本来,Com的类型库和.Net的类型元数据有很大区别,但是由于生成了Com类型库的元数据,相当于托管的代理,称为COM Interop,这样对于开发者来说,是没有区别的,只是在使用的时候有一些注意事项而以。对于程序集的引用,可以在设计开发的时侯添加引用,也可以在运行期动态引用,这就跟早绑定、晚绑定是一个道理了。
非托管资源,MSDN上也没有明确的描述?例如Connection会使用哪些非托管资源?Dispose时这些非托管资源是会被释放的?(会不会有内存泄露?不是我不相信GAC,实在是我遇到的问题太实在了---内存简直就是飙涨)。如下语句===
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");我有点想不通,在mscorlib.dll中就不必写版本和文化、PublicKeyToken?为什么?mscorlib.dll只有一个,难道System.data.dll会有两个?口径为什么会不统一?以下内容载自MSDN 2003 April====
public static Type GetType(string);
[C++] public: static Type* GetType(String*);
[JScript] public static function GetType(String) : Type;
Gets the Type with the specified name, performing a case-sensitive search and specifying whether to throw an exception if an error occurs while loading the Type
这里没有提到用要用完全限定名啊,误导?
楼主,是你让我深深地理解了‘人外有人,天外有天’这句话。谢谢侬!
在看完这帖子以后,我没有立即回复,因为我生怕我庸俗不堪的回复会玷污了这网上少有的帖子。但是我还是回复了,因为觉得如果不能在如此精彩的帖子后面留下自己的网名,那我死也不会瞑目的!能够在如此精彩的帖子后面留下自己的网名是多么骄傲的一件事啊!楼主,请原谅我的自私!
我知道无论用多么华丽的辞藻来形容楼主您帖子的精彩程度都是不够的,都是虚伪的,所以我只想说一句:您的帖子太好看了!我愿意一辈子的看下去!
这篇帖子构思新颖,题材独具匠心,段落清晰,情节诡异,跌宕起伏,主线分明,引人入胜,平淡中显示出不凡的文学功底,可谓是字字珠玑,句句经典,是我辈应当学习之典范。
就小说艺术的角度而言,这篇帖子不算太成功,但它的实验意义却远远大于成功本身。正所谓:“一马奔腾,射雕引弓,天地都在我心中!”楼主真不愧为无厘界新一代的开山怪!
本来我已经对这个社区失望了,觉得这个社区没有前途了,心里充满了悲哀。但是看了你的这个帖子,又让我对社区产生了希望。是你让我的心里重新燃起希望之火,是你让我的心死灰复燃,是你拯救了我一颗拨凉拨凉的心!
本来我决定不会在社区回任何帖子了,但是看了你的帖子,我告诉自己这个帖子是一定要回的!这是百年难得一见的好贴啊!苍天有眼啊,让我在优生之年得以观得如此精彩绝伦的帖子!
楼主,你要继续努力啊!你是社区的希望啊!
-----
------摘自“程序人生版”一贴
我觉得这个回复简直太经典了,所以拿来套用一下。
晕哦。 :o
》》》经常会有人问为什么用了什么什么技术(比如说Remoting)内存一直涨啊?实际上你说的这几个命名空间里面的类确实用到了不少非托管的资源,比如窗口,VM最终还是调用操作系统的API去显示窗口,另外一个例子是数据库连接;对于实际的开发来说,不用到这些东西是不可能的。
没有你所谓的托管和非托管的界限,实际上.Net调用的非托管代码都是在托管环境下执行的,一切都要通过CLR,非托管的代码从某种意义上来说已经被转换为托管代码被执行,但是非托管代码和非托管资源是两个不同的概念;非托管代码是指不是用.Net开发的程序集,比如Com组件,非托管资源是指使用非托管代码创建的不在GAC管理范围内的对象或者其他系统资源,比如文件句柄、数据库连接。
对于托管资源和非托管资源的问题,托管的对象会被GAC回收,但是非托管资源不会,这是因为GAC也管不了,它也不会知道你使用了哪些非托管资源,只有你自己手动去释放。但是,但是,在使用.Net类库的前题下,你自己的代码如果没有明确的访问托管资源,那么你是不需要考虑这个问题的,比如你提到的,你使用System.IO、System.Data下面的一些类去访问文件系统或者数据库,那么那些类在被GAC回收的时侯会处理非托管资源的释放。
MSDN中的说法,是在你自己使用了非托管资源的情况下,比如你自己使用操作系统的API去访问文件系统,那么你就要在对象被回收的时侯释放文件的句柄。你提到的内存使用的问题,我想应该出在别的地方,另外,.Net的程序比较耗内存也是正常的。》》我有点想不通,在mscorlib.dll中就不必写版本和文化、PublicKeyToken?为什么?
实际上这个问题很简单,你看mscorlib的名字就知道,既然是核心库,那么自然有特殊的地方,特殊就特殊在编译器默认会在你的程序集中引用它,这个组件是.Net整个类库的基础,几乎所有的MS官方的装配件都引用了它,所以它的版本实际上也就是你的程序集引用的Framework的版本。
既然它这麽特殊,那这个问题也就很简单了,只是因为装配件默认就会去在它里面查找类型,所以在它里面定义的类型就不需要指定版本和PublicKeyToken了。》》mscorlib.dll只有一个,难道System.data.dll会有两个?口径为什么会不统一?
mscorlib.dll可能会有很多个,这会看你的机器上是否安装了几个不同版本的Framework,其他的Dll自然也是一样
你的担心是有道理的,毕竟元数据中包含了类型的所有信息,包括私有成员、保护成员,通过反射,理论上都是可以访问到这些成员的。
因此,反射中应用了ReflectionPermission来控制反射的访问权限,一般来说,普通的代码使用反射访问类型都受到了“通用类型系统的可访问性规则”的约束,也就是说跟直接调用能够访问的成员是一样的,但是特殊的情况下,装配件可以向代码授予权限来访问该规则之外的,比如保护和私有的成员,如果不具有此权限,代码将无法使用反射通过 Type、Assembly 和 Module 上的 Get 方法来获取有关非公共成员(即使属于它自己的类)的信息。
按照.Net的安全性,一般的使用是没有问题的,关键是如果为其他代码授予了ReflectionPermission权限,那么就需要注意了,因为原则上这样是可以通过反射访问到私有成员的。下面的摘自MSDN:在未经许可的情况下,所有代码都可以使用反射来执行以下任务: 获取有关公共类型及其公共成员的信息。
了解代码所在的模块和程序集。
枚举公共类型。
枚举与使用反射的代码位于同一程序集中的非公共类型。
枚举程序集和模块。
调用公共成员。
对调用代码基类的族访问成员进行调用。
对调用代码程序集的程序集访问成员进行调用。
也没有GetMethod等方法不安全的说法,反射的安全性是建立在.Net安全性的基础上,和几个方法的具体实现没有关系