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

    最近想研究一下反射,先上网找了找资料,几乎大部分都是照抄MSDN的内容,生涩难懂,几乎没说,又找了找,发现一些强人的实例解析,才稍微有了点门道,个人感觉,反射其实就是为了能够在程序运行期间动态的加载一个外部的DLL集合,然后通过某种办法找到这个DLL集合中的某个空间下的某个类的某个成员(通过反射可以访问该类所包含的所有成员,不论成员是公有还是私有),看看网上N人写的实例:

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

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

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

        //这里要用LoadFrom,只有在本工程里添加了该dll的引用后才可以使用Load   
        Assembly objAss = Assembly.LoadFrom(@"D:\Test\HSMP.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();
        }
    }


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

  • 相关阅读:
    Android开发之Sqlite的使用
    ZOJ 3607 Lazier Salesgirl
    ZOJ 3769 Diablo III
    ZOJ 2856 Happy Life
    Ural 1119 Metro
    Ural 1146 Maximum Sum
    HDU 1003 Max Sum
    HDU 1160 FatMouse's Speed
    Ural 1073 Square Country
    Ural 1260 Nudnik Photographer
  • 原文地址:https://www.cnblogs.com/kingcat/p/879873.html
Copyright © 2011-2022 走看看