谈谈:程序集加载和反射

简介:

最近一直都在看关于程序集加载和反射方面的资料, 所以在这里把我所学习到的东西记录下来,方便自己以后复习,也给园子里面不懂的朋友参考。

一、程序集的加载

JIT编译器器将IL代码编译成本地代码时, 会查看IL代码中引用了哪些类型。在运行过程中,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型,然后JIT编译器将对应程序集加载到AppDomain中,在内部,CLR使用System.Reflection.Assembly类的静态方法Load来尝试加载一个程序集。然而如果我们想动态加载一个程序集时,可以使用Assembly的Load方法来动态加载程序集,其中Assembly类中还提供了其他的加载程序集方法,有LoadFrom(string path), LoadFile(stringassemblyFile)等,具体方法的使用和解释可以参照MSDN中的介绍:http://msdn.microsoft.com/zh-cn/library/xbe1wdx9

 

二、反射机制

.net中反射在运行中过程中解析程序集中的元数据,获得类型中的成员(包括字段、构造器、方法、属性、事件等)信息。

动态加载一个程序集并获得类型中的成员

把下面的类放在一个类库工程中,并编译生成程序集(例如为ClassLibrary1.dll,假设把dll放在D盘根目录下面)

View Code
 1  public class ReflectTestClass
 2     {
 3        public  string name;
 4        public int age;
 5        public string Name
 6        {
 7            get { return name; }
 8            set { name = value; }
 9        }
10 
11        public int Age
12        {
13            get { return age; }
14            set { age = value; }
15        }
16 
17         /// <summary>
18         /// No Paramter Constructor
19         /// </summary>
20        public ReflectTestClass()
21        { 
22        }
23 
24         /// <summary>
25         /// Constructor with Parameter
26         /// </summary>
27         /// <param name="name"></param>
28         /// <param name="age"></param>
29         public ReflectTestClass(string names,int ages)
30         {
31             this.name = names;
32             this.age = ages;
33         }
34 
35         public string writeString(string name)
36         {
37             return "Welcome " + name;
38         }
39 
40         public static string WriteName(string name)
41         {
42             return "Welcome "+name +" Come here";
43         }
44 
45         public string WirteNopara()
46         {
47             return "The method is no parameter ";
48         }
49     }

然后建立一个控制台程序用来动态加载上面生成的程序集和输出类型中的成员,代码中有详细的介绍。

class Program
    {
        static void Main(string[] args)
        {
            Assembly ass;
            Type[] types;
            Type typeA;
            object obj;
            try
            {
                // 从本地中 加载程序集 然后从程序集中通过反射获得类型的信息的,并且调用方法
                ass = Assembly.LoadFrom(@"D:\ClassLibrary1.dll");
                types = ass.GetTypes();
                foreach (Type type in types)
                {
                    Console.WriteLine("Class Name is " + type.FullName);
                    Console.WriteLine("Constructor Information");
                    Console.WriteLine("-----------------------");
                    // 获取类型的结构信息
                    ConstructorInfo[] myconstructors = type.GetConstructors();
                    ShowMessage<ConstructorInfo>(myconstructors);

                    Console.WriteLine("Fields Information");
                    Console.WriteLine("-----------------------");
                    // 获取类型的字段信息
                    FieldInfo[] myfields = type.GetFields();
                    ShowMessage<FieldInfo>(myfields);

                    Console.WriteLine("All Methods Information");
                    Console.WriteLine("-----------------------");
                    // 获取方法信息
                    MethodInfo[] myMethodInfo = type.GetMethods();
                    ShowMessage<MethodInfo>(myMethodInfo);

                    Console.WriteLine("All Properties Information");
                    Console.WriteLine("-----------------------");
                    // 获取属性信息
                    PropertyInfo[] myproperties = type.GetProperties();
                    ShowMessage<PropertyInfo>(myproperties);
                }

                // 用命名空间+类名获取类型
                typeA = ass.GetType("ClassLibrary1.ReflectTestClass");
                
                // 获得方法名称

                MethodInfo method = typeA.GetMethod("writeString");

                // 创建实例
                obj = ass.CreateInstance("ClassLibrary1.ReflectTestClass");

                string result = (String)method.Invoke(obj,new string[] {"Tom"});
                Console.WriteLine("Invoke Method With Parameter");
                Console.WriteLine("-----------------------");
                Console.WriteLine(result);
                Console.WriteLine("-----------------------");
                Console.WriteLine();
                method = typeA.GetMethod("WriteName");
                result = (string)method.Invoke(null,new string[] {"Tom"});
                Console.WriteLine("Invoke Static Method with Parameter");
                Console.WriteLine("-----------------------");
                Console.WriteLine(result);
                Console.WriteLine("-----------------------");
                Console.WriteLine();
                method = typeA.GetMethod("WirteNopara");
                Console.WriteLine("Invoke Method with NOParameter");
                result = (string)method.Invoke(obj, null);
                Console.WriteLine("-----------------------");
                Console.WriteLine(result);
                Console.WriteLine("-----------------------");
            }

            catch(FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadLine();
        }

        /// <summary>
        /// 显示数组信息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="os"></param>
        public static void ShowMessage<T>(T[] array)
        { 
            foreach(T member in array)
            {
                Console.WriteLine(member.ToString());
            }

            Console.WriteLine("-----------------------");
            Console.WriteLine();
        }
    }


筛选返回的成员种类

可以调用Type的GetMembers,GetFields,GetMethods,GetProperties或者GetEvenents方法来查询一个类型的成员。在调用上面的任何一个方法时,都可以传递System.Reflection.BindingFlags枚举类型的一个实例,使用这个枚举类型目的是对这些方法返回的成员进行筛选。对于这个枚举类型中成员的信息可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/system.reflection.bindingflags(v=VS.80).aspx

注意:在返回一个成员集合的所有方法中, 都有一个不获取任何实参的重载版本。如果不传递BindingFlags实参,所有这些方法都返回公共成员,默认设置为BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static. (如果指定Public或NonPublic,那么必须同时指定Instance,否则不返回成员)。




     本文转自LearningHard 51CTO博客,原文链接:http://blog.51cto.com/learninghard/1034784,如需转载请自行联系原作者




相关文章
|
4月前
|
Java 测试技术 Android开发
Android项目架构设计问题之使用反射调用类的私有方法如何解决
Android项目架构设计问题之使用反射调用类的私有方法如何解决
31 0
|
开发框架 缓存 安全
C#OOP之十三 组件、程序集与反射
C#OOP之十三 组件、程序集与反射
72 0
|
索引
07-OC底层原理之类的加载流程
07-OC底层原理之类的加载流程
39 0
|
存储 缓存 前端开发
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
127 0
(十八) 反射的原理是什么,反射创建类实例的三种方式是什么?
javac在这一阶段会把java代码编译为class文件,保存在硬盘中,这个文件中保存着这个类的类名、成员名、构造方法、其他方法等。
|
Web App开发 API
引用同一个项目中的类库,如何避免 goToDefinition时不能到达真正的定义类
新建一个解决方案: Api 添加类库 APi.Data APi.Data 新建一个 Entity public class Entity {private int id;public int Id {get { return id; }set { id = value;...
743 0