.NET基础:利用反射原理实现动态创建对象

.NET中利用反射原理实现动态创建对象

1.静态创建创建对象一般是创建类库,其中包含各种类,类中有各种方法,在所需的程序及调用时一般采用 类库名.类名 命名= new类库名.类名(); 命名.方法名(); 的方式调用 例如:

Weapon.Staff stf = new Weapon.Staff();//静态创建对象
            stf.Hit();

但在已完成的程序中添加新项时对代码改动需要比较大 所以有了动态创建对象

2.动态创建对象:

过程概述:通过assembly类获取到文件的集合,添加到Type表单中(即元数据),如果获取的是所有的对象则用GetTypes();如果是根据类型的名字(字符串之类的),获取这种类型的Type对象,则用GetType(name);可以根据获取的对象类型类动态从本地或者远程动态创建对象类型。。 则用 Activator.CreateInstance(获取的类型名);创建实例,创建的实例是object类型的所以前面要加object ;通过获取的类型名可以获取该类型下的所有成员 则用 MemberInfo[] meminfo=类型名.GetMembers();  GetMembers()用来获取所有成员 GetMember(单个成员);GetMethods();获取所有的方法 GetMethods(方法名); MethodInfo hitMothod = 类型名.GetMethod(方法名);根据方法名字(字符串),获取该类型的方法成员实例   hitMothod.Invoke(obj, null);//调用obj这个对象的hitmothod所指向的方法

本次通过小例子来解释说明(vs2013) 创建一个空白解决方案,创建一个窗体程序ReflectDemo 和类库 Weapon weapon中有两个类Staff Sword 都有相同的方法

 public void Hit()
        {
           System.Windows.Forms.MessageBox.Show("staff:员工 不同的类中显示的字不同");
        }

将类库生成,在windowsfrom程序下添加对该程序类的引用,同时添加命名空间 using System.Reflection;

下面是windowsfrom中的代码及解释 窗体中共有三个button1 2 3,和两个listbox 1 2

在button1

private void button1_Click(object sender, EventArgs e)
        {          
          //反射
            //从D盘上把名字叫Weapon.dll的程序集,加载到内存里
            Assembly asm = Assembly.LoadFile(@"D:\Weapon.dll");//D\\Weapon
            Type[] types = asm.GetTypes();//相当于程序清单 表单 获取所有
            foreach (Type item in types)//循环遍历到listbox1中
            {
                this.listBox1.Items.Add(item.ToString());
            }
        }
在button2事件下
 private void button2_Click(object sender, EventArgs e)
        {
            string wpName = this.listBox1.Text;
            Assembly asm = Assembly.LoadFile(@"D:\Weapon.dll");
            Type wptype = asm.GetType(wpName);//根据类型名字(字符串),获取这种类型的Type对象(模板)
            Object obj = Activator.CreateInstance(wptype);
            //动态创建对象 Activator:从本地或远程创建对象类型,或获取对现有远程对象的引用(不可继承)
            MemberInfo[] memList = wptype.GetMembers();//GetMembers返回Systeam.Type的所有公共成员即(字段 属性 方法 索引 委托 事件)
            //menberINfo获取有关成员属性的信息并提供对成员元数据的访问  GetMembers所有成员 GetMember单个成员 GetMethods所有方法 GetMethod单个方法
            foreach (MemberInfo item in memList)
            {
                this.listBox2.Items.Add(item.Name);//item 的获取项很多
            }
        }

在button3事件下

private void button3_Click(object sender, EventArgs e)
        {
            //接下来就是实例化对象 调用方法实现相关需要
            string wpName = this.listBox1.Text;
            Assembly asm = Assembly.LoadFile("D:\\Weapon.dll");
            Type wpType = asm.GetType(wpName);//根据类型名字(字符串),获取这种类型的Type对象(模板)
            Object obj = Activator.CreateInstance(wpType);//动态创建对象
            string methodName = this.listBox2.Text;//拿到你想调用的那个方法的名字
            MethodInfo hitMothod = wpType.GetMethod(methodName);//根据方法名字(字符串),获取该类型的方法成员实例
            hitMothod.Invoke(obj, null);//调用obj这个对象的hitmothod所指向的方法

        }

按照如上代码便能实现最原始的动态创建实例对象,其中的关于代码的解释已标注。

3.改进,每一个事件中都需要对dll进行访问,在此将统一化 高内聚低耦合

方法:首先在app.config

<appSettings>
    <add key="AssemblyPath" value="D:\Weapon.dll"/> //物理路径地址
</appSettings>

同时在from的程序下添加如下代码,同时添加引用System.Configuration

        private Assembly asm = null;
        public Form1()
        {
            InitializeComponent();
            string asmPath = System.Configuration.ConfigurationManager.AppSettings["AssemblyPath"];
           asm = Assembly.LoadFile(asmPath);
        }
然后把每一个button事件下的

 Assembly asm = Assembly.LoadFile(@"D:\Weapon.dll");

删除即可

4.再次改进,有一些实例化对象是固定的,不需要这么复杂的动态创建 所以可以用接口来实现

如果是反射的得到实例对象,那么他的默认引用类型是object的
如果想把这个object类型的对象强制转换成接口类型(反射出来的对象必须实现了这个接口)
那么这个接口不能与被反射的类,写在同一个项目里
必须把这个接口写在一个独立的项目里。

在原来的类库那重新创建一个类库,命名为ICommon即接口总类 其中定义一个接口类IHitable写入一个

 public interface IHitable
    { 
        void Hit();
    }

同时生成之后在类库中添加对该接口类库的引用 同时在该类库中所有类前加一个继承关系,继承自何种接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ICommon;

namespace Weapon
{
    public class Staff : IHitable
    {
        public void Hit()
        {
           System.Windows.Forms.MessageBox.Show("staff:员工 嗯当法杖");//这个是要添加引用 System.Windows.Forms.
        }
    }
}

同时在主窗体程序中修改button3中的代码 ;同时需要在主程序中添加对该接口dll的引用和using命名空间的引用

 private void button3_Click(object sender, EventArgs e)
        {
            //接下来就是实例化对象 调用方法实现相关需要
            string wpName = this.listBox1.Text;
          //  Assembly asm = Assembly.LoadFile("D:\\Weapon.dll");
            Type wpType = asm.GetType(wpName);//根据类型名字(字符串),获取这种类型的Type对象(模板)
            Object obj = Activator.CreateInstance(wpType);//动态创建对象
            //string methodName = this.listBox2.Text;//拿到你想调用的那个方法的名字
            //MethodInfo hitMothod = wpType.GetMethod(methodName);//根据方法名字(字符串),获取该类型的方法成员实例
            //hitMothod.Invoke(obj, null);//调用obj这个对象的hitmothod所指向的方法

            ICommon.IHitable wp = obj as ICommon.IHitable;
            wp.Hit();
        }

猜你喜欢

转载自blog.csdn.net/Lsc_hei/article/details/79745841