• C#反射教程(2)


    解析

      反射技术在运行时可以获取程序集中每个类型的成员,包括字段、方法、属性、事件等,并进一步获取这些成员的详细信息。反射技术还可以动态载入外部程序集(私有程序集或共享程序集),获取程序集中类型的相关数据。有意思的是从外部动态载入的程序集还可通过晚期绑定,创建外部程序集中某类型的实例(对象),并且可以进一步调用其成员(如方法和属性)。在这个过程中,并不知道外部程序集的任何信息(甚至不知道该程序集是否存在)。

      简而言之,反射技术以编程的方式获取程序集的元数据信息,通常情况下,只能通过ildasm.exe程序载入程序集或模块,才能读取其元数据。 NET的反射技术从程序集中获取各种细节类型元数据(如FieldInfo类描述了字段的细节)实例,并做进一步的操作,而这些细节类型大多数属于 System.Reflection命名空间。

      说明:ildasm.exe是.Net Framework自带的程序,用于查看程序集的IL代码、元数据等信息。假设C盘是系统分区,则ildasm.exe程序通常位于C:/WINDOWS /Microsoft.NET/ Framework/v2.0.50727目录下。

      System.Reflection命名空间包含了很多与反射有关的类型,通过这些类型可以获取指定类型的所有细节。本题要求获取指定类型中方法的完整信息,而System.Reflection命名空间下关于方法的类型为MethodInfo类型和ParameterInfo类型,所以只需要获取指定类型中方法的这2个类相关的对象即可。要达到这个目的,需要获取表示指定类型元数据的Type对象,Type对象即System.Type类的实例,该对象的成员可以返回System.Reflection命名空间下的类型,包括MethodInfo类型和ParameterInfo类型。在前面的示例中使用了对象的GetType方法获取类型名称,除此之外,还有多种获取Type对象的方法,如以下代码所示:

    +展开
    -C#
    //调用对象的GetType方法获取Type对象的引用
    Type 对象引用变量 = 对象.GetType();
    //调用Type类GetType静态方法的不同重载版本
    Type 对象引用变量 = System.Type.GetType("类型的全饰名称");
    Type 对象引用变量 = System.Type.GetType("类型的全饰名称"
    是否抛出异常, 是否不区分大小写);
    Type 对象引用变量 = System.Type.GetType("类型的全饰名称, 
    类型所属程序集的友好名称");
    //使用C#的typeof运算符
    Type 对象引用变量 = typeof(类型名称);


      以上代码,调用Type类的GetType()静态方法,其中第3个重载版本用于获取外部私有程序集类型的Type对象。当获取指定类型的Type对象后,就可以通过其成员返回MethodInfo类型和ParameterInfo类型,以达到获取方法完整信息的目的,如以下代码所示:

    +展开
    -C#
    using System;
    using System.Reflection;

    MethodInfo[] 方法数组 = Type.GetType("类型的全饰名称"falsefalse);
    使用foreach语句遍历方法数组的每个子项,即可访问类型中方法的所有信息;
    //在foreach语句中,调用方法数组子项的GetParameters方法,可返回ParameterInfo类型的参数数组
    ParameterInfo参数数组 = 方法数组子项.GetParameters();
    使用foreach语句遍历参数数组的每个子项,即可访问方法中参数的所有信息;


    以上代码使用了foreach语句,可访问方法中参数的所有信息。

      注意:默认情况下,反射只能获取公共成员的信息,而访问非公共成员可能会带来安全危险。因此,访问非公共成员的代码需要带有适当标志的 ReflectionPermission。此外,某些任务(例如执行非托管代码和序列化对象)还需要SecurityPermission。

      面试例题7:如何利用反射获取当前程序集指定类型的信息?

      考点:反射技术获取类型信息的方法以及获取类型成员集合的方法。

      出现频率:★★

      解答

      获取指定类型的信息只需要获取该类型的Type对象,然后调用其成员即可。获取执行代码封装于ClassB类的静态方法Ref()中,用户输入不同的值,反射不同类型的详细信息。在目录下新建一个程序文件,并命名为ClassRef.cs,编写代码如代码7.7所示。

    代码7.7 反射指定类型的信息:ClassRef.cs

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

    class ClassRef
    {
    static void Main(string[] args)
    {        
    while (true)
    {
    Console.Write("请输入所检测的类型名称:");
    //接收用户输入值并赋值给input变量
    string input = Console.ReadLine();
    //如果用户输入"quit",则跳出循环
    if (input == "quit")
    {
    break;
    }
    try
    {
    //调用Type类的静态方法GetType,并将Type对象引用返回给tp变量
    Type tp = Type.GetType(input, falsefalse);
    //调用ClassB的Ref静态方法,并传递tp对象
    ClassB.Ref(tp);
    }
    //捕获空对象引用异常
    catch (NullReferenceException e)
    {
    //输出异常信息
    Console.WriteLine("异常信息:{0}", e.Message);
    }
    //捕获一般异常
    catch (Exception e)
    {
    //输出异常信息
    Console.WriteLine("异常信息:{0}", e.Message);
    }
    }
    }
    }
    //定义2个接口类型IClassA和IClassB
    public interface IClassA
    {
    string MethodA(string s);
    }
    public interface IClassB
    {
    string Name
    {
    get;
    }
    }
    //定义ClassA,该类继承于接口类型IClassA和IClassB
    class ClassA : IClassA,IClassB
    {
    public string _name;
    public string Name
    {
    get
    {
    return _name;
    }
    }
    //定义internal权限的MethodA方法
    public string MethodA(string s)
    {
    _name = s;
    return _name;
    }
    //定义public权限的MethodB方法
    public ClassA(string s)
    {
    Console.WriteLine("所接收的参数是:{0}", s);
    }
    }
    class ClassB
    {
    string _name;
    //定义internal权限的MethodB方法
    internal string MethodB(string s)
    {
    _name = s;
    return _name;
    }
    //定义静态方法Ref,接收1个Type类型的参数
    public static void Ref(Type tp)
    {
    //输出Type对象的基本属性
    string FullName = tp.FullName;
    Console.WriteLine("/n/t============={0}类型的信息=============", FullName);
    Console.WriteLine("{0}是泛型类型吗?->{1}", FullName, tp.IsGenericType);
    Console.WriteLine("{0}是接口类型吗?->{1}", FullName, tp.IsInterface);
    Console.WriteLine("{0}是类类型吗?->{1}",FullName,tp.IsClass);
    Console.WriteLine("{0}是COM对象吗?->{1}", FullName, tp.IsCOMObject);
    Console.WriteLine("{0}是public访问类型吗?->{1}", FullName, tp.IsPublic);
    Console.WriteLine("{0}是密封类型吗?->{1}", FullName, tp.IsSealed);
    Console.WriteLine("{0}是值类型吗?->{1}", FullName, tp.IsValueType);
    //获取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);
    }

    }
    }
  • 相关阅读:
    20155327 2017-2018-2 《Java程序设计》第9周学习总结
    20155327《Java程序设计》第八周学习总结
    实验二 Java面向对象程序设计
    20155327 李百乾 Exp4 恶意代码分析
    20155327结对编程练习
    20155327第七周学习总结
    2017-2018-1 20155310 20155337 实验五 通讯协议设计
    # 2017-2018-1 20155337《信息安全系统设计基础》第十三周学习总结
    # 20155337 2017-2018 1 课上测试、课下作业、实验
    # 课下测试ch02
  • 原文地址:https://www.cnblogs.com/cpcpc/p/2123072.html
Copyright © 2020-2023  润新知