C#锐利体验 第十六讲 映射
来源:互联网 发布:卡玛d1c知乎 编辑:程序博客网 时间:2024/04/27 08:47
C#锐利体验
南京邮电学院 李建忠(lijianzhong@263.net.cn)
第十六讲 映射
动态类型查询
我们知道,C#编译后的PE文件主要由IL代码和元数据组成,元数据为.NET组件提供了丰富的自描述特性,它使得我们可以在代码运行时获知组件中的类型等重要的信息。在C#中这是通过一种称作映射(Reflection)的机制来完成的。先来看一个示例,我们首先创建一个简单的类型:
// SimpleType.cs
public class MyClass
{
private int count=100;
public int Count
{ get{ return count; }
set{ count=value; }
}
public void Print()
{ System.Console.WriteLine(count);}
}
用编译命令csc /t:library SimpleType.cs编译上面的文件得到SimpleType.dll输出。我们再来实现查询类型的测试程序:
//Test.cs
using System;
using System.Reflection;
class Test
{
public static void
{
Type t = typeof(MyClass);//获取MyClass的类型信息
Console.WriteLine("The Type Name : {0}",t.Name);//获取类型的名字
FieldInfo[] fiArr=t.GetFields();//获取所有的共有域
Console.Write("The {0} Fields :",fiArr.Length);
foreach(FieldInfo o in fiArr)
{
Console.Write(o.Name+" ");
}
Console.WriteLine();
PropertyInfo[] piArr=t.GetProperties();//获取所有的公有属性
Console.Write("The {0} Properties :",piArr.Length);
foreach(PropertyInfo o in piArr)
{
Console.Write(o.Name+" ");
}
Console.WriteLine();
MethodInfo[] miArr=t.GetMethods();//获取所有的公有方法
Console.Write("The {0} Methods :",miArr.Length);
foreach(MethodInfo o in miArr)
{
Console.Write(o.Name+" ");
}
}
}
用编译命令csc /r:simpletype.dll test.cs编译后,执行可得到下面的输出:
The Type Name : MyClass
The 0 Fields :
The 1 Properties :Count
The 7 Methods :GetHashCode Equals ToString get_Count set_Count Print GetType
在上面的例子中,我们首先通过 typeof(MyClass)获得类MyClass的类型信息,当然我们也可以通过创建对象实例,然后调用对象实例的GetType方法来获得(每个类都从object根类中继承获得此方法)。在拥有了类型信息(变量t)后,我们便可以获得其类型的名字,该类型含有的公有域,公有属性,公有方法。注意这里C#的映射机制只允许我们获取类型的公有信息,这符合面向对象的封装的原则。这也是为什么我们虽然我们实现了count域,查询类型得到的输出却是“The 0 Fields :”——如果将SimpleType.cs中的count域改为public公有,我们将会得到他的查询信息。其中4个方法(GetHashCode Equals ToString GetType)都是继承自object类的公有方法,而方法get_Count 和set_Count则是我们在实现Count属性的“副产物”——这符合我们前面讲述的属性本质上为方法的变体。实际上,System.Type类各种各样的成员使得我们能够获得几乎所有的与类型相关的公有信息。在System.Reflection命名空间下的各个类更是可以获得各个编程元素更较详细的信息,如方法的参数与返回值,域的类型,枚举的各个值等。
动态创建与调用
实际上映射还远远不止于动态地获知组件的类型信息,它还能使我们在获得类型信息的基础上,在代码运行时进行类型的动态创建与方法的动态调用,甚至于动态地创建并执行IL代码!
动态调用为C#的组件提供了晚绑定功能,它使得组件之间在运行时的集成变得极为方便!利用前面创建的简单的组件SimpleType.dll,我们来看一看怎样完成对象的动态创建和方法的动态调用:
// DynamicExe.cs
using System;
using System.Reflection;
class Test
{
public static void
{
Assembly a=Assembly.LoadFrom("SimpleType.dll");//装载组件
foreach(Type t in a.GetTypes())
{
if(t.IsClass && !t.IsAbstract)
{
MethodInfo[] miArr=t.GetMethods();//获得类型的公有方法
object o=Activator.CreateInstance(t);//创建实例(无参构造器)
foreach(MethodInfo mi in miArr)
{
if(!mi.IsAbstract && !mi.IsStatic
&& mi.GetParameters().Length==0)
{
object re=mi.Invoke(o,null);//调用实例方法
Console.WriteLine("{0} , Return :{1}",mi.Name,re);
}
}
}
}
}
}
用编译命令csc /r:simpletype.dll dynamicexe.cs编译后,执行可得到下面的输出:
GetHashCode , Return :8
ToString , Return :MyClass
get_Count , Return :100
100
Print , Return :
GetType , Return :MyClass
我们在上面的例子给出了被动态调用的方法的名字和返回值。其中输出的第4行为100,它是我们动态调用方法MyClass.Print() 的输出。需要指出的是我们通过一定的控制,仅仅调用的是类型的公有的无参数的实例方法。给出组件的名字,运用Assembly.LoadFrom我们便可以动态的装载组件。Activator.CreateInstance允许动态地创建类型(我们这里只通过无参的构造器来创建),实际上用它创建出来的类型和我们用MyClass o=new MyClass()创建出来的类型一模一样。进而,我们便可以在查询到的成员的基础上,对它们进行动态调用。
Microsoft.NET从底层的元数据设计入手,为映射机制提供了非常坚实的基础。命名空间System.Reflection和System.Reflection.Emit为操作这种映射提供了实实在在的强大的API编程接口,大大改善了组件的设计环境,提高了组件的交互能力!
- C#锐利体验 第十六讲 映射
- C#锐利体验第一讲
- C#锐利体验 第六讲 方法
- C#锐利体验 第十七讲 异常处理
- C#锐利体验 第十一讲 数组
- C#锐利体验 第十二讲 字符串
- C#锐利体验 第十四讲 枚举
- C#锐利体验 第十五讲 特征
- C#锐利体验-第六讲 方法(转)
- C#锐利体验 第二讲 C#语言基础介绍
- C#锐利体验之第二讲 C#语言基础介绍
- C#锐利体验-第二讲 C#语言基础介绍(转)
- C#锐利体验 第一讲 “Hello,World!”程序
- C#锐利体验 第三讲 Microsoft.NET平台基础构造
- C#锐利体验 第四讲 类与对象
- C#锐利体验 第五讲 构造器与析构器
- C#锐利体验 第七讲 域与属性
- C#锐利体验 第十八讲 非安全代码
- 也许我是对的~~
- 写在C++图书出版史上又一部经典著作问世之前
- 3章
- [职场] 职业规划和职业生涯的模式
- 演示从注册表中还原MSNMessenger口令
- C#锐利体验 第十六讲 映射
- [职场] 职业生涯规划的几个关键点
- C#锐利体验 第十七讲 异常处理
- Java 库的建立方法及其实例
- C#锐利体验 第十八讲 非安全代码
- 使用设计模式改善程序结构
- Java中的等式
- 一种纯Java的数据库—JDataStore
- my luck to meet u....