C#锐利体验 第十六讲 映射

转载 2004年09月03日 20:01:00

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 <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Main(string[] args)
    {
        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 Main()
    {
        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.ReflectionSystem.Reflection.Emit为操作这种映射提供了实实在在的强大的API编程接口,大大改善了组件的设计环境,提高了组件的交互能力!

第十六讲:运算符重载

重载运算符 关键字operator 运算符分可重载运算符和不可被重载运算符 运算符重的主要用处是扩展运算符的运算能力 运算符其实也是一种特殊的方法,只不过参数列表的呈现有些不同 ...
  • wljhk2006
  • wljhk2006
  • 2014年03月13日 16:14
  • 262

第十六讲:多重继承

第十六讲:多重继承     * 掌握:继承与派生的概念以及继承的分类。     * 理解:多重派生的构造函数;初始化基类成员的使用。     * 了解:纯虚函数和动态联编。     重点、难点...
  • L_cpp
  • L_cpp
  • 2016年09月08日 14:15
  • 161

体验套餐管理系统

1.3/// //定义几个检查项目 CheckItem sg, tz, sl, tl, ggn, bc, xdt; //定义一个系统默认的检查套餐“入学体检” ...
  • wuji3390
  • wuji3390
  • 2017年05月08日 18:02
  • 434

C#实现对象映射

有时候会遇到这样的问题,两个对象具有很多相同的属性,已知一个对象,要给另外一个对象赋值,这时候需要每个属性逐一赋值,会比较麻烦。 如果不考虑性能问题的话,可以使用对象映射的方式来赋值,实际上是利用了反...
  • u010655942
  • u010655942
  • 2015年10月31日 20:05
  • 4264

Linux运维第十六讲

1.当/boot下的东西都被删除后 (网络引导和CD引导均可以用,在使用CD引导之前,我在虚拟机上直接从真机上lftp得到了kernel) chroot /mnt/sysimage grub2-...
  • qq_31813491
  • qq_31813491
  • 2017年03月01日 18:23
  • 71

第十六讲:菜单 Android Menu

本讲内容:菜单 menu  1、选项菜单 OptionsMenu  2、上下文菜单 ContextMenu  3、子菜单 SubMenu 组成Android用户界面的除了View以外,还有...
  • rongwenbin
  • rongwenbin
  • 2014年08月01日 18:08
  • 305

C#中通过映射对MySQL数据进行操作

首先,C#中通过映射对MySQL数据进行操作需要导入:FlunetNHibernate.dll和NHibernate.dll这两个程序集;引用方法: 选择联机搜索,然后点击安装就可以了; 右键添加新...
  • CJB_King
  • CJB_King
  • 2016年11月17日 13:57
  • 1476

c# 内存共享、内存映射文件、适合读取大文件

using System;   using System.Collections.Generic;   using System.Text;   using System.Runtime....
  • newnazi
  • newnazi
  • 2013年08月03日 21:49
  • 1418

NHibernate 继承映射(第十六篇)

在NHibernate的映射中,关于继承的映射策略有3种方式 单表继承类表继承具体表继承   另外还有一种比较特别的多态映射 隐式多态   下面分别来阐述NHibernate继...
  • mss359681091
  • mss359681091
  • 2016年09月21日 17:25
  • 223

C# .Net 共享内存 内存映射文件 Memory Mapped 转

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing...
  • ldp365
  • ldp365
  • 2015年03月17日 16:38
  • 808
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#锐利体验 第十六讲 映射
举报原因:
原因补充:

(最多只允许输入30个字)