码迷,mamicode.com
首页 > 其他好文 > 详细

反射 | 程序集

时间:2015-05-18 06:40:20      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:

什么是程序集:
程序集是。net中的概念,net中dll和exe都是程序集,他们的区别就是exe可以直接执行(因为它有入口main函数,而dll没有,)而dll 不可以直接执行,它没有入口main函数,它是供其他程序来调用的

控制台应用程序最后编译成了exe文件,而类库编译生成了dll文件

什么是放射:

放射就是通过编程的方式,动态加载程序集,并获取里面类型,并创建对象,调用其成员的过程,这就是反射


《1》 我们来首先在解决方案下创建一个类库,命名为“TestDll”  代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestDll
{
    public class Person
    {
        public Person(string name,int age,string email)
        {
            this.Name = name;
            this.Age = age;
            this.Email = email;
        }

        public Person()
        {

        }
        public string Name { get; set; }

        public int Age { get; set; }

        public string Email { get; set; }

        public void Say()
        {
            Console.WriteLine("Hi.....");
        }

        public void SayHello()
        {
            Console.WriteLine("Hi,我是SayHello无参数重载方法!");
        }

        public void SayHello(string msg)
        {
            Console.WriteLine(msg);
        }

        public int Add(int x, int y)
        {
            return x + y;
        }
    }

    public interface IFlyable
    {
        void Fly();
    }

    public class Student : Person
    { 
        
    }
    internal class Teacher : Person
    { 
    
    }
    public class MyClass1:IFlyable
    {

        public void Fly()
        {
            Console.WriteLine("");
        }
    }
    public delegate void MyDelegate();

    public struct MyStruct
    { 
    
    }
    struct MyStruct1
    { 
    
    }
}

《2》我们创建一个控制台应用程序,来练习一下这个放射如何使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射
{
    public class MyClass
    {
        public string Name { get; set; }

        public void Say()
        {
            Console.WriteLine("你好......");
        }

        private void SayHello()
        {
            Console.WriteLine("大家好才是真的好");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            
            //对于Type的介绍

            //1.怎么获取一个类型的Type  (即:该类型的类型原数据),办法有两种

            //1.1当有类型的对象的时候的获取方式

            MyClass mc = new MyClass();
            Type t1= mc.GetType();  //这样就获得了MyClass类型的Type

            //1.2只有类,没有类型对象的时候
            Type t2 = typeof(MyClass); //这样就获得了MyClass类型的Type


            //-----------------------那么拿到这个Type能干啥?-----------------------//

            //1可以获取当前类型的父类是谁?
            Console.WriteLine(t1.BaseType.ToString());

            //可以获取当前的类型的父类的父类是谁?
            //Console.WriteLine(t1.BaseType.BaseType.ToString());
            
            //2获取当前类型中的所有公有字段
            FieldInfo[] fieldinfo= t1.GetFields();

            //3获取当前类型中的所有公有属性
            PropertyInfo[] propertyinfo= t1.GetProperties();

            //4获取当前类型中的所有公有方法
            MethodInfo[] methodinfo = t1.GetMethods();

            //5获取当前类型中的所有公有事件
            EventInfo[] eventinfo = t1.GetEvents();

            //6获取当前类型中的所有公有构造函数
            ConstructorInfo[] constructorinfo = t1.GetConstructors();

            //................等等


            












            //---------------------------------------------//
            
            //动态加载程序集  (Assembly类表示一个程序集,它是一个抽象的类,它里面有些静态成员)
            //根据程序的路径,动态加载一个程序集
            Assembly asm=Assembly.LoadFile(@"D:\学习\Solution1\TestDll\bin\Debug\TestDll.dll");

            //获取该程序集中的所有类型
            Type[] types= asm.GetTypes();

            foreach (var v in types)
            {
                //Console.WriteLine(v.FullName); //获取该程序集中所有类型的名称,打印产生如下输出
                /*
                 TestDll.Person
                 TestDll.IFlyable
                 TestDll.Student
                 TestDll.Teacher
                 TestDll.MyClass1
                 TestDll.MyDelegate
                 TestDll.MyStruct
                 TestDll.MyStruct1                
                 */
            }


            //我们一般我们只获取程序集中的所有公有类型(即:获取程序集中所有public的类型)
            Type[] publicTypes = asm.GetExportedTypes();

            foreach (var v in publicTypes) 
            {
                Console.WriteLine(v.FullName); //打印一下,产生如下输出
                /*
                 TestDll.Person
                 TestDll.IFlyable
                 TestDll.Student
                 TestDll.MyClass1
                 TestDll.MyDelegate
                 TestDll.MyStruct
                 */
            }

            //-------有时候我们只需要获取某个类型 比如我们现在想获取这个Person类型-------------//


            Type ptype = asm.GetType("TestDll.Person"); //注意:括号中应该带上Person类的命名空间TestDll; 即:命名空间+类名



            //-------------------现在我们来调用Person类中的Say()方法---------//


            //想调用Person类中的Say()方法就先获取这个Say()方法
            MethodInfo methodA = ptype.GetMethod("Say");

            //拿到了这个Say()方法了,然后我们就调用这个Say()方法....可以怎么调用呢?

            //methodinfo.Invoke这个方法是用来调用Say()这个方法的,可是它里面有两个参数,
            //第一个参数:表示Say()这个方法所属的类的对象; 因为Say()方法是非静态方法,非静态方法只有类对象才能调用
            //第二个参数:表示Say()这个方法的参数,如果没有参数就写个null就可以了。因为一个方法可以有多个参数,所以它是一个object的数组类型

            //问题来了,既然我们想得到Say()这个方法所属的类的对象,我们又法直接方法Person类型,所以不能直接new一个Person类型的对象,我们又另外一种方法来创建Person类型的对象
            object objA=Activator.CreateInstance(ptype); //这样就会根据这个ptype创建了Person类的一个对象

            methodA.Invoke(objA, null); //在这里就是调用了这个Say方法 输出:Hi.....




            //---------------现在我们来调用Person类中的SayHello()的无参数重载方法------------//

            MethodInfo methodB = ptype.GetMethod("SayHello", new Type[] { }); //注意 第二个参数表示SayHello()这个方法的参数,因为方法可以有多个参数,所有第二个参数是一个数组,而我在数组里什么都没有放,即放了一个空数组,就表示获取Person类下面没有参数的SayHello()方法
            object objB = Activator.CreateInstance(ptype);
            methodB.Invoke(objB,null);


            //--------------现在我们来调用Person类中的SayHello()有1个参数的重载方法---------//

            MethodInfo methodC = ptype.GetMethod("SayHello", new Type[] { typeof(string) }); //获取SayHello()这个方法中有一个string类型的参数的方法
            object objC = Activator.CreateInstance(ptype);
            methodC.Invoke(objC, new object[] {"参数1" }); //输出:参数1








            //-------------------------通过Type来创建对象----------------//

            
            //我们上面有样式过 根据Person的Type创建一个Person类型对象
            object objD = Activator.CreateInstance(ptype);

            //但是通过以上这种方式来创建对象也是有一点问题的。因为如果这个Person没有无参构造函数,只有一些有参数的构造函数,我想通过调用一些有参数的构造函数来创建对象,这个时候使用Activator.CreateInstance(ptype);就不行了,因为这里Activator.CreateInstance(ptype);就是调用无参构造函数创建对象的,它没发指定有参构造函数来创建对象,所以我们只能通过另外一种办法来创建

           
            //-------通过调用指定的构造函数来创建对象---------

            //1.获取指定的构造函数
            ConstructorInfo info = ptype.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(string) });

            //2.调用构造函数来创建对象
            object objE =info.Invoke(new object[] { "张三", 25, "123@qq.com" }); //这个objeE就是通过指定构造函数来创建的对象

            //通过放射获取指定对象的属性的值 比如这里我要获取Person类的Name属性值

            //1.首先的获取这个Person类下面的Name属性
            PropertyInfo pinfo = ptype.GetProperty("Name");

            string name=pinfo.GetValue(objE, null).ToString(); //获取objE这个对象的Name属性值

            Console.WriteLine(name);

            //同样我们也可以设置属性的值
            pinfo.SetValue(objE, "李四"); //设置objE这个对象的Name属性值

            string name2 = pinfo.GetValue(objE, null).ToString();

            Console.WriteLine(name2); //输出一下重新设置的Name值
            

            Console.ReadKey();

            
        }
    }
}


反射 | 程序集

标签:

原文地址:http://blog.csdn.net/fanbin168/article/details/45798967

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!