• 动态的加载类型


    开篇先熟悉两个小概念:

    早绑定:是指在编译时绑定对象的类型

    晚绑定:是指在运行时才绑定对象的类型。

    当然我们提到上面两个概念,肯定是为了引入今天的主题——利用反射实现晚绑定(也就是动态的加载类型,并调用它们)。

    我暂时只是为了测试的方便先定义一个不能执行的程序集(Person.dll)无需写的完善,仅仅作为测试使用,之后我们在这个程序中调用它。

    person.dll内部如下:

    person.dll
     1  using System;
     2     public class Chinese
     3     {
     4         private string language;
     5         private string name;
     6         private int age;
     7         private string like;
     8         public string Like
     9         {
    10             get { return like; }
    11             set { like = value; }
    12         } 
    13         public string Language
    14         {
    15             get { return language; }
    16             set { language = value; }
    17         }
    18         public string Name
    19         {
    20             get { return name; }
    21             set { name = value; }
    22         }
    23         public int Age
    24         {
    25             get { return age; }
    26             set { age = value; }
    27         }
    28         public virtual void Favourite()
    29         {
    30             Console.WriteLine(name+"今年"+age+岁"喜欢的运动是:"+this.like);
    31         }
    32         public Chinese()
    33         { 
    34         }
    35         public Chiese(string name, int age)
    36         {
    37             this.name = name;
    38             this.age = age;
    39         }
    40     }

    注意:当我们不用vs生成注意程序集的时候,一定要注意主程序运行时不能低于该程序集的运行时,默认的使用命令提示执行时使用的是最新的运行时:例如:我这里执行了:

    之后执行主程序报错,于是更新了一下运行时版本就OK了。

    如果我们这样定义:就会发生早绑定,因为编译时,编译器将从程序集中导入Chinese类。

    Chiesep1=new Chiese("小强",18);

    那么我们怎么实现晚绑定呢?

    现在我们再看下开篇晚绑定的概念,也就是说我们这里实现的效果是:不会再元数据中嵌入对类型的引用,而是在运行是通过反射来实现。现在我们就开始动态加载类型和调用方法。先看一种方式:

    1. 使用Assembly类的Load方法来动态的来动态的加载指定的程序集。
    2. 使用Assembly类的GetType方法来动态的加载指定的类型。
    3. 通过Type类的InvokeMember方法来调用Type对象所表示的类型方法。

    下面的代码演示如歌动态的加载程序集Person.dll,动态的加载Chinese类型,并调用Favourite方法:

     1 using System;
     2 using System.IO;
     3 using System.Reflection;
     4 
     5 namespace 动态的加载类型
     6 {
     7     class Program
     8     {
     9         static void Main()
    10         {
    11             //加载程序集
    12             string assemblyPath = Path.Combine(Environment.CurrentDirectory, "person.dll");
    13             Assembly a = Assembly.LoadFrom(assemblyPath);
    14            //获取指定的类型
    15             Type t = a.GetType("Chinese");
    16            //构造类型实例
    17             Object[] args = new Object[] { "小强",18 };
    18             Object obj = t.InvokeMember(null,
    19                 BindingFlags.DeclaredOnly |                       //指定绑定类型
    20                 BindingFlags.Public | BindingFlags.NonPublic |
    21                 BindingFlags.Instance | BindingFlags.CreateInstance, null, null, args);
    22             Console.WriteLine("新创建的类型: " + obj.GetType().ToString());
    23             Console.WriteLine("================");
    24             //给字段like赋值
    25             t.InvokeMember("like",
    26            BindingFlags.DeclaredOnly |
    27            BindingFlags.Public | BindingFlags.NonPublic |
    28            BindingFlags.Instance | BindingFlags.SetField, null, obj, new Object[] { "抓篮球" });
    29             //调用方法
    30             t.InvokeMember("Favourite", BindingFlags.DeclaredOnly |
    31             BindingFlags.Public | BindingFlags.NonPublic |
    32             BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, null);
    33             Console.ReadKey();
    34         }
    35     }
    36 }

    利用System.Activator类

        承接上面的实例更简单的加载类型的方法,就是利用System.Activator类。

    该类包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。此类不能被继承。

    步骤如下: 

    1.加载程序集并调用GetType方法获取目标类型对象

    2.调用Activator.CreateInstance(Type)使用指定类型的默认构造函数来创建该类型的实例,并通过Type对象的GetMethod方法来获取MethodInfo对象

    3.使用MethodInfo对象的Invoke方法来动态的执行方法。

     1 using System;
     2 using System.Reflection;
     3 
     4 namespace Test
     5 {
     6     class Program
     7     {
     8         static void Main()
     9         {
    10             Assembly a = Assembly.Load("person.dll");
    11             Type t = a.GetType("Chinese");
    12             Object[] args = new Object[] { "小强", 18 };
    13             object obj = Activator.CreateInstance(t, args);
    14             MethodInfo mi = t.GetMethod("Favourite");
    15             mi.Invoke(obj, null);
    16             Console.ReadKey();
    17         }
    18     }
    19 }

    执行效果图:

  • 相关阅读:
    Laravel实用小功能
    _initialize() 区别 __construct()
    PHP websocket之聊天室实现
    原来PHP对象比数组用更少的内存
    PHP协程
    mongodb数据库的导出与导入
    我理解的数据结构(一)—— 数组(Array)
    Swoole 源码分析——Server模块之Worker事件循环
    PHP面试:说下什么是堆和堆排序?
    我理解的数据结构(二)—— 栈(Stack)
  • 原文地址:https://www.cnblogs.com/rohelm/p/2473333.html
Copyright © 2020-2023  润新知