zoukankan      html  css  js  c++  java
  • C#反射教程(4)

    面试例题8:如何动态加载外部程序集并用反射获取指定类型的信息?

    考点:学习动态加载外部程序集的基本方法,理解Assembly类的Load()方法和LoadFrom()方法的区别。

    出现频率:★★★

    解答

      通过System.Reflection命名空间下的Assembly类可以动态加载外部程序集,可选方法为Load()方法和 LoadFrom()方法。Load()方法用于加载当前程序集位于相同目录下的外部程序集,LoadFrom()方法可以加载其他目录中的程序集。以上示例中的ClassRef.exe程序作为需要加载的外部程序集,进一步获取其指定类型的信息。在目录下新建一个程序文件,并命名为 AppClassRef.cs,编写代码如代码7.8所示。

    代码7.8 动态加载外部程序集:

    +展开
    -C#
    using System;
    //导入相应的命名空间
    using System.Reflection;
    using System.IO;

    class AppClassRef
    {
    static void Main(string[] args)
    {
    //查看当前应用程序域的所有程序集
    DisAllAm();
    while (true)
    {
    Console.Write("请输入所检测的类型名称:");
    //接收用户输入值并赋值给input变量
    string input = Console.ReadLine();
    //如果用户输入"quit",则跳出循环
    if (input == "quit")
    {
    break;
    }
    //声明Assembly类型对象am
    Assembly am;
    try
    {
    //调用Assembly类的Load方法,将引用传递给am
    am = Assembly.Load("ClassRef");
    //以下代码调用Assembly类的LoadFrom方法
    //am = Assembly.LoadFrom(@"D:/web/NET/ClassRef.exe");
    //调用am的GetType方法,并将Type对象引用返回给tp变量
    Type tp = am.GetType(input, falsefalse);
    //调用ClassB的Ref静态方法,并传递tp对象
    ClassB.Ref(tp);
    }
    //捕获文件未找到异常
    catch (FileNotFoundException e)
    {
    //输出异常信息
    Console.WriteLine("异常信息:{0}", e.Message);
    }
    //捕获空对象引用异常
    catch (NullReferenceException e)
    {
    //输出异常信息
    Console.WriteLine("异常信息:{0}", e.Message);
    }
    //捕获一般异常
    catch (Exception e)
    {
    //输出异常信息
    Console.WriteLine("异常信息:{0}", e.Message);
    }
    finally
    {
    //再次查看当前应用程序域的所有程序集
    DisAllAm();
    }
    }
    }
    //定义DisAllAm方法,用于显示程序集列表
    static void DisAllAm()
    {
    Console.WriteLine("/n/t=============当前应用程序域中所有加载的程序集=============");
    //通过GetAssemblies方法获取当前应用程序域的所有程序集
    foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
    {
    //输出程序集的名称
    Console.WriteLine("程序集:{0}", a.FullName);
    }
    }
    }
    class ClassB
    {
    //定义静态方法Ref,接收一个Type类型的参数
    public static void Ref(Type tp)
    {
    //输出Type对象的基本属性
    string FullName = tp.FullName.ToString();
    Console.WriteLine("/n/t============={0}类型的信息=============", FullName);
    //获取Type对象的所有公共成员并保存到mi数组
    MemberInfo[] mi = tp.GetMembers();
    //遍历并输出mi数组所有的子项属性
    foreach (MemberInfo m in mi)
    {
    Console.WriteLine("/t成员类别->{0},名称->{1}",m.MemberType, m.Name);
    }
    //获取Type对象所实现的接口并保存到Itp数组
    Type[] Itp = tp.GetInterfaces();
    //判断Itp数组是否有子项,如果有则输出子项属性
    if (Itp.Length != 0)
    {
    foreach (Type t in Itp)
    {
    Console.WriteLine("{0}实现的接口类型->{1}", FullName, t.FullName);
    }
    }
    else
    {
    Console.WriteLine("{0}不实现的任何接口类型", FullName);
    }
    }
    }


      本题的类型信息输出和ClassRef.exe相同,这里不作过多讲述。主程序中首先调用了DisAllAm()静态方法,该方法封装了列举当前应用程序域所含程序集列表的代码。在命令行下编译AppClassRef.cs执行AppClassRef程序,运行结果如图7.13所示。

      本程序首先输出了当前应用程序域所包含程序集的列表,可知当前仅有mscorlib程序集和AppClassRef程序集被加载。继续操作,再次调用DisAllAm()方法,所输出的程序集列表中已经加入了ClassRef程序集。

    图7.13 动态加载外部程序集

    注意:mscorlib程序集包含了.NET大部分的基类库,CLR运行时自动加载。

    解析

      程序动态加载外部程序集,通过System.Reflection命名空间下的Assembly类实现,该类的Load()方法和 LoadFrom()方法可以在运行时加载指定的外部程序集。加载外部程序集后,Assembly类将创建相应的对象,调用该对象的GetType()方法可获取指定类型的详细信息。假设加载D:/根目录下的MyApp.exe程序集,并且定义Assembly类的对象am,其如以下代码所示:

      序直接输出了ClassA类的细节信息。再次输入"ClassB",程序输出ClassB类的细节信息,运行结果如图7.10所示。

    +展开
    -C#
    using System;
    //导入相应的命名空间
    using System.Reflection;
    using System.IO;

    Assembly am;
    try
    {
    am = Assembly.Load("MyApp");
    Type tp = am.GetType("指定类型名称",false,false);
    }
    catch (FileNotFoundException e)
    {
    Console.WriteLine("异常信息:{0}", e.Message);
    }


      以上代码调用了Assembly类的Load()方法载入MyApp程序集(exe或dll),代码正常加载的前提是当前程序集和MyApp程序集位于相同目录。所以,Assembly类的LoadFrom()方法也比较常用,其编写方法如下所示:

    +展开
    -C#
    am = Assembly.LoadFrom("D:/MyApp.exe");


      可见,Assembly类的LoadFrom()方法需要传递外部程序集的完整路径。当外部程序集加载后,可以通过访问当前应用程序域的所含程序集,以确定加载是否成功。需要注意System.IO命名空间的导入,因为主程序中需要捕捉"文件未找到"的异常,防止外部程序集不存在。

      说明:读取AppDomain类的CurrentDomain属性,可返回当前应用程序域,调用当前应用程序域的GetAssemblies方法,可获取所包含程序集的集合。

    面试例题9:如何通过晚期绑定调用方法成员?

    考点:晚期绑定的含义,晚期绑定的基本方法。

    出现频率:★★★

    解答

      晚期绑定即在编译时不能确定是否存在类型,在运行时创建该类型的实例,调用其成员。本例程序分别定义了3个外部类型,编译为dll程序集,由 LateBinding.cs代码动态加载,调用其内部方法。在目录下新建一个程序文件,并命名为OldClass.cs,编写代码如代码7.9所示。

    代码7.9 第1个外部类:OldClass.cs

    +展开
    -C#
    public class OldClass
    {
    //定义public权限的Method静态方法
    public static string Method(string s)
    {
    string output = "OldClass类的Method静态方法返回结果:" + s;
    return output;
    }
    }


    在目录下新建一个程序文件,并命名为NewClass.cs,编写代码如代码7.10所示。

    代码7.10 第2个外部类:NewClass.cs

    +展开
    -C#
    public class NewClass
    {
    //定义public权限的Method实例方法
    public string Method(string s)
    {
    string output = "NewClass类的Method实例方法返回结果:" + s;
    return output;
    }
    }


    在目录下新建一个程序文件,并命名为MyClass.cs,编写代码如代码7.11所示。

    代码7.11 第3个外部类:MyClass.cs

    +展开
    -C#
    public class MyClass
    {    
    //定义public权限的Method实例方法
    public string Method(string s)
    {
    string output = "MyClass类的Method实例方法返回结果:" + s;
    return output;
    }
    //定义public权限的MethodTxt实例方法
    public string MethodTxt()
    {
    string output = "MyClass类的MethodTxt无参数实例方法被调用";
    return output;
    }
    }
  • 相关阅读:
    【英语】Bingo口语笔记(40)
    【英语】Bingo口语笔记(38)
    【Python系统学习】基础篇
    【英语】Bingo口语笔记(37)
    [转]linux下ulimit命令详解
    【转】linux read 用法
    【转】Linux下使用locale命令设置语言环境
    【转】基于linux下的变量声明declare的用法
    [转]Linux中set,env和export这三个命令的区别
    linux下echo命令详解(转)
  • 原文地址:https://www.cnblogs.com/cpcpc/p/2123070.html
Copyright © 2011-2022 走看看