zoukankan      html  css  js  c++  java
  • .NET基础拾遗(5)反射1

    1.反射产生的背景

        对无法直接添加引用的程序集中类型元素的动态获取和使用。使用场景如插件开发,vs本身的智能提示。

    2.反射的基本原理

      依托于元数据,运行时动态获取并构建程序集、模块、类型及字段等目标对象并调用目标对象(如调用方法,属性赋值)的机制

        元数据,就是描述数据的数据。在CLR中,元数据就是对一个模块定义或引用的所有东西的描述系统。

                   也就是代码架构,vs中选择一个类型,按f12转到定义。

    3.反射的作用

         1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata);

         2、迟绑定(Late-Binding)方法和属性。3、动态创建类型实例(并可以动态调用所创建的实例的方法、字段、属性)

    4 .反射的基础--运行时类型标识

    • 运行时类型标识(RTTI),可以在程序执行期间判定对象类型。
    • 运行时类型标识,能预先测试某个强制类型转换操作,能否成功,从而避免无效的强制类型转换异常。 
    • 在c#中有三个支持RTTI的关键字:is 、 as  、typeof。 
    •  is运算符:

      通过is运算符,能够判断对象类型是否为特顶类型,如果两种类型是相同类型或者两者之间存在引用,装箱拆箱转换,则表明两种类型是兼容的。

    •  as运算符:

       在运行期间执行类型转换且能够使得类型转换失败不抛异常,而返回一个null值。

    • typeof运算符: 

       as ,is 能够测试两种类型的兼容性。但大多数情况下需要获得某个类型的具体信息就用到了typeof,它返回与具体类型相关的System.Type对象一旦获得给定类型的Type对象,就可以通过使用该对象定义的各种属性,字段,方法来获取类型的具体信息

    4 .反射的核心类:System.Type

    这个类封装了关于对象的信息,获得了类型的Type对象后,就可根据Type提供的属性和方法获取此类型的一切信息(方法、字段、属性、事件、参数、构造函数等)

    获取Type对象有两种形式,一种是获取当前加载程序集中的类型(Runtime),一种是获取没有加载的程序集的类型。

    我们先考虑Runtime时的Type,一般来说有三种获取方法:

    2.1使用Type类提供的静态方法GetType()

    Type t = Type.GetType("System.IO.Stream");
    txtOutput.Text = t.ToString();

    注意到GetType方法接受字符串形式的类型名称。

    2.2 使用 typeof 操作符

    // 如果在页首写入了using System.IO; 也可以直接用 typeof(Stream);
    Type t = typeof(System.IO.Stream);

    这时的使用有点像泛型,Stream就好像一个类型参数一样,传递到typeof操作符中。

    2.3 通过类型实例获得Type对象

    String name = "Jimmy Zhang";
    Type t = name.GetType();

    使用这种方法时应当注意,尽管我们是通过变量(实例)去获取Type对象,但是Type对象不包含关于这个特定对象的信息,仍是保存对象的类型(String)的信息。

    5 .反射程序集

    在.Net中,程序集是进行部署、版本控制的基本单位,它包含了相关的模块和类型,只是讲述如何通过反射获取程序集信息。

    在System.Reflection命名空间下有一个Assembly类型,它代表了一个程序集并包含了关于程序集的信息。

    在程序中加载程序集时,我们可以使用 Assembly类型提供的静态方法LoadFrom() 和 Load(),比如:

    Assembly asm = Assembly.LoadFrom("Demo.dll");

    或者

    Assembly asm = Assembly.Load("Demo");

    当使用LoadFrom()方法时提供的是程序集的文件名,当将一个程序集添加到项目引用中以后,可以直接写“文件名.dll”。

    如果想加载一个不属于当前项目的程序集,则需要给出全路径,比如:

    Assembly asm = Assembly.LoadFrom(@"C:WINDOWSMicrosoft.NETFrameworkv2.0.50727System.Web.dll");

    使用Load()方法的时候,只用提供程序集名称即可,不需要后缀名。

    如果想获得当前程序集,可以使用Assembly类型的静态方法 GetExecutingAssembly,它返回包含当前执行的代码的程序集(也就是当前程序集)。

    Assembly as = Assembly.GetExecutingAssembly();

    在获得一个Type类型实例以后,我们还可以使用该实例的Assembly属性来获得其所在的程序集:

    Type t = typeof(int)
    Assembly asm = t.Assembly;

     一个程序集可能有多个模块(Module)组成,每个模块又可能包含很多的类型,但.Net的默认编译模式一个程序集只会包含一个模块。

     

        [Serializable]
        class SimpleClass
        {
            private String _MyString;
            public SimpleClass(String mystring)
            {
                _MyString = mystring;
            }
    
            public override string ToString()
            {
                return _MyString;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine("简单程序集");
                Console.Read();
            }
        }
    
        public class AnalyseHelper
        {
            /// <summary>
            /// 分析程序集
            /// </summary>
            public static void AnalyzeAssembly(Assembly assembly)
            {
                Console.WriteLine("程序集名字:" + assembly.FullName);
                Console.WriteLine("程序集位置:" + assembly.Location);
                Console.WriteLine("程序集是否在GAC中:" +
                            assembly.GlobalAssemblyCache.ToString());
                Console.WriteLine("包含程序集的模块名" +
                    assembly.ManifestModule.Name);
                Console.WriteLine("运行程序集需要的CLR版本:" +
                    assembly.ImageRuntimeVersion);
                Console.WriteLine("现在开始分析程序集中的模块");
                Module[] modules = assembly.GetModules();//assembly也可以直接获取所有类型调用.gettypes()
                foreach (Module module in modules)
                {
                    AnalyzeModule(module);
                }
            }
    
            /// <summary>
            /// 分析模块
            /// </summary>
            public static void AnalyzeModule(Module module)
            {
                Console.WriteLine("模块名:" + module.Name);
                Console.WriteLine("模块的UUID:" + module.ModuleVersionId);
                Console.WriteLine("开始分析模块下的类型");
                Type[] types = module.GetTypes();
                foreach (Type type in types)
                {
                    AnalyzeType(type);
                }
            }
    
            /// <summary>
            /// 分析类型
            /// </summary>
            public static void AnalyzeType(Type type)
            {
                Console.WriteLine("类型名字:" + type.Name);
                Console.WriteLine("类型的类别是:" + type.Attributes);
                if (type.BaseType != null)
                    Console.WriteLine("类型的基类是:" + type.BaseType.Name);
                Console.WriteLine("类型的GUID是:" + type.GUID);
                //设置感兴趣的类型成员
                BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                //分析成员
                FieldInfo[] fields = type.GetFields(flags);
                if (fields.Length > 0)
                {
                    //Console.WriteLine("开始分析类型的成员");
                    foreach (FieldInfo field in fields)
                    {
                        // 分析成员
                    }
                }
                //分析包含的方法
    // MethodInfo类派生于MethodBase抽象类,而MethodBase类继承了MemberInfo类 MethodInfo[] methods = type.GetMethods(flags); if (methods.Length > 0) { //Console.WriteLine("开始分析类型的方法"); foreach (MethodInfo method in methods) { // 分析方法 } } //分析属性 PropertyInfo[] properties = type.GetProperties(flags); if (properties.Length > 0) { //Console.WriteLine("开始分析类型的属性"); foreach (PropertyInfo property in properties) { // 分析属性 } } }
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        class Program
        {
            static void Main(string[] args)
            {
    //加载程序集 Assembly assembly = Assembly.LoadFrom(@"......SimpleAssemblyinDebugSimpleAssembly.exe"); AnalyseHelper.AnalyzeAssembly(assembly); // 创建一个程序集中的类型的对象 Console.WriteLine("利用反射创建对象"); string[] paras = { "测试一下反射效果" }; object obj = assembly.CreateInstance(assembly.GetModules()[0].GetTypes()[0].ToString(), true, BindingFlags.CreateInstance, null, paras, null, null); Console.WriteLine(obj); Console.ReadKey(); } }

    上面代码按照 程序集->模块->类型 三个层次的顺序来动态分析一个程序集,当然还可以继续递归类型内部的成员,最后通过CreateInstance方法来动态创建了一个类型,这些都是反射经常被用来完成的功能,执行结果如下图所示:

  • 相关阅读:
    c++3种内存管理方式
    什么是向上兼容和向下兼容?
    回溯法解马的遍历问题
    c++内联函数
    2009年NCRE考试有新变化
    sql server日期时间函数
    Web开发工具大集合
    javascript屏幕高度和宽度等信息代码
    gridview无数据行时显示表头的方法
    IE, FF, Safari前端开发常用调试工具
  • 原文地址:https://www.cnblogs.com/tiantianle/p/5767950.html
Copyright © 2011-2022 走看看