zoukankan      html  css  js  c++  java
  • C# 反射/映射学习

    反射其实就是为了能够在程序运行期间动态的加载一个外部的DLL集合,然后通过某种办法找到这个DLL集合中的某个空间下的某个类的某个成员(通过反射可以访问该类所包含的所有成员,不论成员是公有还是私有)

    1.运用反射调用其它程序集中的方法:   
      假设另一个工程中的所有类都编译到一个dll文件中了,在这很多的类当中,有一个类叫StringUtil,名称空间在HSMP.CommonBasic.Common 代码如下 :

    namespace lab.CommonBasic.Common
    {
        class StringUtil
        {
            public double GetSum(double x, double y)
            {
                return x + y;
            }   
        }
    }

    编译后dll文件的存放路径是:D:TestHSMP.CommonBasic.dll   
      现在的问题是,如何通过程序调用该dll文件中的GetSum方法   
      大概有以下几步:

    //这里要用LoadFrom,只有在本工程里添加了该dll的引用后才可以使用Load   
        Assembly objAss = Assembly.LoadFrom(@"D:TestHSMP.CommonBasic.dll");
    
        //HSMP.CommonBasic.Common.StringUtil类的全路径   
        Type t = objAss.GetType("HSMP.CommonBasic.Common.StringUtil");
    
        //动态生成类StringUtil的实例   
        object obj = System.Activator.CreateInstance(t);
    
        //参数信息,GetSum需要两个int参数   
        System.Type[] paramTypes = new System.Type[2];
        paramTypes[0] = System.Type.GetType("System.Int32");
        paramTypes[1] = System.Type.GetType("System.Int32");
    
        //找到对应的方法   
        MethodInfo p = t.GetMethod("SayHello", paramTypes);
    
        // 也可以不给类型参数,下面调用时给实参就可以
        MethodInfo p = t.GetMethod("SayHello");
    
        //参数值,如果所调用的方法没有参数,不用写这些   
        Object[] parameters = new Object[2];
        parameters[0] = 3;
        parameters[1] = 4;
    
        //如果没有参数,写null即可。 
        object objRetval = p.Invoke(obj, parameters);

     通过代码可以看出反射其实很简单。就是动态类型加载。

       

        以上我们用反射对静态类型做加载,但如果类是个范型类该怎么办呢?其实方法大同小异,只是获取到类型时需要设置一下实际要使用的类型即可,先看范型类定义:

    namespace lab.CommonBasic.Common
    {
        class StringUtil<T,U>
        {
            public string GetSum(T x, U y)
            {
                return x + " and " + y;
            }   
        }
    }

    再看反射操作:

    ... 前面代码相同
    
        //HSMP.CommonBasic.Common.StringUtil类的全路径(范型类最后用 `2 标示需要2个范型类型参数)   
        Type t = objAss.GetType("HSMP.CommonBasic.Common.StringUtil`2");
    
        // 这一步很重要,设置实际的范型类型
        t = t.MakeGenericType(new Type[2] { typeof(string), typeof(string) });
    
        //动态生成类StringUtil的实例   
        object obj = System.Activator.CreateInstance(t);
    
        ... 后面代码相同

    还有一种情况,如果类是常类,但方法是范型方法改怎么办?非常简单:

    ... 前面代码相同
    
        //HSMP.CommonBasic.Common.StringUtil类的全路径(范型类最后用 `2 标示需要2个范型类型参数)   
        Type t = objAss.GetType("HSMP.CommonBasic.Common.StringUtil`2");
    
        // 这一步要去掉,因为类不是泛型类所以不能给类设置范型类型
        //t = t.MakeGenericType(new Type[2] { typeof(string), typeof(string) }); 
        ... 中间代码相同     // 区别在这里,把类级别的范型类型设置放到方法级别就可以了。    MethodInfo p = t.GetMethod("SayHello");
        MethodInfo p = p.MakeGenericMethod(new Type[2] { typeof(string), typeof(string) });
        ... 后面代码相同

    2.动态加载, 更改, 增加...某个程序集
      下面例子中, ChangeValue类的myValue本是私有字段, 
      一般情况下在类外部是不能改它的值的, 但利用反射就能直接访问私有字段而不需要通过包装器

    class ChangeValue
    {
        // 这是私有字段
        private string myValue;
    
        // 一般只有通过这样的公共属性外面才可能访问私有字段
        public ChangeValue(string str)
        {
            myValue = str;
        }
        public void WriteLine()
        {
            Console.WriteLine("MyValue is: " + myValue);
        }
    }
    
    class Test
    {
        public static void Main(string[] args)
        {
            // 正常访问
            ChangeValue cv = new ChangeValue("old value");
            cv.WriteLine();
    
            //反射的方法直接访问私有字段
            Type t = cv.GetType();
    
            //得到私有字段对象并赋值
            FieldInfo field = t.GetField("myValue", BindingFlags.NonPublic | BindingFlags.Instance);
            field.SetValue(cv, "new value");
    
            //输出的是新值 "new value"
            cv.WriteLine();
        }
    }

    注:用反射加载的DLL必须要和项目同编译环境(即相同环境编译)

     打个比方, 你要写一个播放器, 要支持如mp3, wmv, avi...等格式, 你还希望用户能自己安装一个新的格式, 也就是我们常说的插件.
    在实现这些, 可能你要将每种格式都写成单个的解码程序集, 如 mp3.dll, wmv.dll, avi.dll....  这样当播放时, 根据扩展名去动态调用相应的解码程序集, 那么这时你就得用反射去动态加载这些dll了.如: Assembly.LoadFile ("...avi.dll"), 然后通过反射可以用avi.dll里面定义的类了.

  • 相关阅读:
    WebApi下载附件文件
    zabbix
    redis主从与集群搭建
    redis
    mariadb集群配置(主从和多主)
    使用python执行sql语句和外键解析
    mariadb(四)连接查询,视图,事物,索引,外键
    mariadb(三)查
    mariadb(二)增删改
    firewalld
  • 原文地址:https://www.cnblogs.com/bohetang/p/4037457.html
Copyright © 2011-2022 走看看