通过反射动态创建对象、方法
之前做的都是获取特性对象,都是查元数据的信息,现在我们可以通过反射开始动态的去创建对象和方法
1.两种调用无参构造函数的方法:
创建一个DemoClass,里面有无参构造函数和有参构造函数
public class DemoClass { public string Name { get; set; } public int Age { get; set; } public DemoClass() { Console.WriteLine("无参构造函数被调用啦"); } public DemoClass(string name,int age) { this.Name = name; this.Age = age; Console.WriteLine("有参构造函数被调用了"); } }
(1)通过Assembly无参构造函数创建对象
Assembly assembly= Assembly.GetExecutingAssembly(); object o =assembly.CreateInstance("使用构造函数创建对象.DemoClass");
CreateInstance方法的第一个参数代表了要创建的类型实例的字符串名称(命名空间+类名)。注意到CreateInstance方法返回的是一个Object对象,如果使用还要强制转换一下。
(2)通过用Activator创建对象
object o2 = Activator.CreateInstance(null, "使用构造函数创建对象.DemoClass");
其中CreateInstance的第一个参数是程序集的名称,为null时表示当前程序集;第二个参数是要创建的类型名称。Activator.CreateInstance返回的是一个ObjectHandle对象,必须执行一次Unwrap()才能返回Object类型,进而可以强制转换成其实际类型。ObjectHandle包含在System.Runtime.Remoting命名空间中,可见它是Remoting相关的,实际上ObjectHandle类只是一个对原类型进行了一个包装以便进行封送
运行结果如下:
3.调用带参构造函数创建对象
使用Assembly的createInstance函数进行对象的创建
public class Program { static void Main(string[] args) { Assembly assembly= Assembly.GetExecutingAssembly(); object[]paramers=new object[2];//创建参数数组,以便传入 paramers[0] = ".net"; paramers[1] = 14; object o =assembly.CreateInstance("使用构造函数创建对象.DemoClass",true,BindingFlags.Default,null,paramers,null,null); DemoClass demo = (DemoClass)o; Console.WriteLine("输出对象的信息:Name"+demo.Name+" Age"+demo.Age); Console.ReadKey(); } }
BindingFlags.Default不使用任何类型搜索策略。执行结果:
4.动态调用方法
在上面的DemoClass中添加两个方法
public int Add(int x, int y) { Console.WriteLine("实例方法被调用"); return x + y; } public static void Add(double x, double y) { Console.WriteLine("静态函数被调用"); }
(1)Type.InvokeMember调用实例方法
public class Program { static void Main(string[] args) { Type t = typeof(DemoClass); DemoClass demo=new DemoClass(); object[]parameters={1,2}; object result=t.InvokeMember("Add", BindingFlags.InvokeMethod, null, demo, parameters); Console.WriteLine("调用实例方法返回的结果:"+result); Console.ReadKey(); } }
第一个参数是指要调用的方法名,第二个参数是要调用方法,第三个Bingder几乎永远传null,第四个是指要在哪个实例上操作,咱们新建的对象demo,最后一个参数是方法的传入参数。InvokeMember方法被调用后返回执行结果。
(2)使用Type.InvokeMember调用静态方法
public class Program { static void Main(string[] args) { Type t = typeof(DemoClass); object[]parameters={1.0,2.0}; object result=t.InvokeMember("Add", BindingFlags.InvokeMethod, null, t, parameters); Console.ReadKey(); } }
调用静态方法时与调实例方法差别在第四个参数上,调静态方法只需要传递类型就可以。
5.使用MethodInfo.Invoke调用方法
先获取一个MethodInfo实例,然后调用该实例的Invoke方法
(1)调用实例方法
public class Program { private static void Main(string[] args) { Type t = typeof(DemoClass); object[] parameters = { 1, 2 }; DemoClass demo = new DemoClass(); MethodInfo info = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public); info.Invoke(demo, parameters); Console.ReadKey(); } }
因为方法中存在多个“Add”方法,所以在GetMethod中加BindingFlags中是必要的,Invoke方法第一个参数是要在那个实例上调用该方法,第二个参数时参数列表。Invoke返回方法执行结果。
(2)调用静态方法
public class Program { private static void Main(string[] args) { Type t = typeof(DemoClass); object[] parameters = { 1, 2 }; MethodInfo info = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public); info.Invoke(null, parameters); Console.ReadKey(); } }
调用静态方法与实例方法的区别在于在用BingdingFlags进行搜索时要指定搜索Static,另外Invoke的时候不需要再传入类型的实例了。
6.迟绑定
在我们项目中,各个插件实现了同一个插件接口,再运行时动态的去加载哪个插件,如果不使用反射动态调用的情况下,只能去写多个if else了。编译器在运行前根本不知道去执行哪个方法,称为迟绑定。