zoukankan      html  css  js  c++  java
  • C# 反射实现动态加载程序集

    原文:https://blog.csdn.net/pengdayong77/article/details/47622235

    在.Net 中,程序集(Assembly)中保存了元数据(MetaData)信息,因此就可以通过分析元数据来获取程序集中的内容,比如类,方法,属性等,这大大方便了在运行时去动态创建实例。

     反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

    主要用途:

    1. 动态加载DLL,实现插件机制。
    2. 实例化DLL中的类型。
    3. 执行后期绑定,访问在运行时创建的类型的方法。

    今天我就介绍下后面的两个用途,其实最初的目的只是想根据配置文件中的值创建对应对象。

    Dll

    先上一段代码,这是要调用的ClassGreenerycn类,它被编译为DllDemo.dll。

        using System;
     
        namespace DllDemo
        {
            public class ClassGreenerycn
            {
                public string Name { get; set; }
                public bool IsTest { get; set; }
                public void Hello()
                {
                    Console.WriteLine(Name);
                }
            }
        }

    很简单的代码,就是一个类中有两个属性,Hello方法会向命令行中输出Name的名称。

    使用反射创建Dll中的类实例并调用方法

    现在再新建一个命令行的工程,该工程就一个用途,动态加载DllDemo.dll,然后实例化一个Name为Greenerycn,IsTest为True的对象,并调用Hello方法。

    详细步骤如下:

    1.引用反射的命名空间:

    using System.Reflection;

    2.动态加载Dll

    动态加载Dll有3个函数:

    public static Assembly Load(string assemblyString);
    • 该方法传入的是Dll的名字,该Dll必须位于全局缓存GAC中才行,不然会报“System.IO.FileLoadException: 未能加载文件或程序集”的异常。
    public static Assembly LoadFile(string path);
    • 这个LoadFile最方便,参数就是dll的路径。
    public static Assembly LoadFrom(string assemblyFile);
    • 这个方法也可以,参数同样是dll路径。

    3.获取ClassGreenerycn类的类型

    var type = asm.GetType("DllDemo.ClassGreenerycn");

    注意,这里需要完整的类型名称,包括签名的命名空间。

    4.创建该类型的实例

    var instance = asm.CreateInstance("DllDemo.ClassGreenerycn");

    5.设置属性

    type.GetProperty("Name").SetValue(instance, "http://greenerycn.cnblogs.com", null);
    type.GetProperty("IsTest").SetValue(instance, true, null);

    6.获取Hello方法

    var method = type.GetMethod("Hello");

    7.调用Hello方法

    method.Invoke(instance, null);

    8.编译运行

    reflaction_demo

    完整的代码

    using System.Reflection;
    
    namespace ReflectionDllDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                var asm = Assembly.LoadFile(@"d:3_codeDotNetDllDemoDllDemoinDebugDllDemo.dll");
    
                var type = asm.GetType("DllDemo.ClassGreenerycn");
    
                var instance = asm.CreateInstance("DllDemo.ClassGreenerycn");
    
                type.GetProperty("Name").SetValue(instance, "http://greenerycn.cnblogs.com", null);
                type.GetProperty("IsTest").SetValue(instance, true, null);
    
                var method = type.GetMethod("Hello");
                method.Invoke(instance, null);
            }
        }
    }
    ---------------------


    //在外部动态库和本地类继承同一抽象类AbstractHi并实现同一接口interface 的情况下(甚至接口引用相同实体),主要用于加载不同类名,但实际签名相同的方法的类
    
    //实体
     public class Person
        {
             public string Name {get ;set}
        }
    //1.创建接口
        public interface IHi
        {
            string SayHi();
            Person GetPerson();
        }
    //2.抽象类继承接口
        public abstract class AbstractHi : IHi
        {
            public abstract string SayHi();
            public abstract Person GetPerson();
        }
    -----------------------------------------------
    //3.动态库实现(dll文件)
        public class DllDemo : AbstractHi
        {
            public override string SayHi()
            {
                return "Hi";
            }
            public override Person GetPerson()
            {
                var person  =new Person ();
                Person.Name = "MyName";
                return person  ;
            }
        }
    ------------------------------------------------
    //4.加载动态库
            /// <summary>
            /// 返回操作对象,加载类名包含defaultClass字符串的类
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="defaultClass"></param>
            /// <returns></returns>
            public static T GetDllDemo<T>(string defaultClass) where T : class
            {
                try
                {
                    var asm = Assembly.LoadFile(@"d:3_codeDotNetDllDemoDllDemoinDebugDllDemo.dll");
                    var dllDemo = (from d in asm.DefinedTypes
                        where d.BaseType.FullName.Contains(defaultClass)
                        select d.FullName
                    ).FirstOrDefault();
                    var type = asm.GetType(dllDemo);
                    return Activator.CreateInstance(type) as T;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
    //5.实例化
            public class DllDemoBLL
            {
                private AbstractHi_DAL
                public DllDemoBLL()
                {
                    _DAL = GetDllDemo<AbstractHi>("DllDemo");
                }
                public string SayHi2()
               {
                    return _DAL. SayHi();
                }
               public  Person GetPerson2()
               {
                    return _DAL. GetPerson();
                }
            }
    //6.调用
            private DllDemoBLL _BLL = new DllDemoBLL();
    
            public string SayHi3()
            {
                return _BLL.SayHi2();
    //最终返回 "Hi"
            }      
       public Person GetPerson3()
            {
                return _BLL.GetPerson2();
    //最终返回 Person 属性Name=“MyName” 的实体
            }                                       
     
  • 相关阅读:
    @PathVariable和@RequestParam的区别
    Spring整合hibernate4:事务管理
    Android横竖屏切换生命周期
    Android-Universal-Image-Loader三大组件DisplayImageOptions、ImageLoader、ImageLoaderConfiguration详解
    Gson简要使用笔记
    Java Web 路径问题
    Java相对路径/绝对路径总结
    关于图片或者文件在数据库的存储方式归纳
    cf706C(dp)
    cf414B(dp)
  • 原文地址:https://www.cnblogs.com/zhang1f/p/11680737.html
Copyright © 2011-2022 走看看