一个例子:C#语言使用反射调用指定类内的函数
jopen
9年前
今天研究了一下,当指定程序集、类全名、方法名时,给定一个该类的实例,如何调用该实例中指定的方法。
这个功能的背景是这样的:
1、程序中有多个窗体(都继承自Form),保存在一个数组中
2、因为作为父类的Form我是不能新加入任何方法的,所以代码都是现在每个具体的页面里,也就是说,我们只能在子类中写代码,而不能在基类中写代码
3、每个页面(如FormA、FormB)都有一个功能,实现一个同一名称的函数
4、获取FormA、FormB的实例后,要做到调用这些页面内在第3步中指定名称的函数
这个功能抽象一下,可以表述为:给定程序集、类名、指定的函数名,我们要想办法在得到这个类的实例时,调用到指定的函数
示例程序如下:
设立一个程序集InvokeTester
里面实现基类Vehicle
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace InvokeTester { public class Vehicle { public Vehicle(string brand, string model) { this.Brand = brand; this.Model = model; } /// <summary> /// 商标 /// </summary> private string _brand; /// <summary> /// 商标 /// </summary> public string Brand { get { return _brand; } private set { _brand = value; } } /// <summary> /// 型号 /// </summary> private string _model; /// <summary> /// 型号 /// </summary> public string Model { get { return _model; } private set { _model = value; } } } }
Vehicle下有子类Truck:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace InvokeTester { public class Truck : Vehicle { public Truck(string brand, string model, string purpose) : base(brand, model) { this.Purpose = purpose; } /// <summary> /// 用途 /// </summary> private string _purpose; /// <summary> /// 用途 /// </summary> public string Purpose { get { return _purpose; } private set { _purpose = value; } } public string GetDescription() { return string.Format("商标:{0},型号:{1},用途:{2}", Brand, Model, Purpose); } } }
现在要做的,是在一个以Vehicle类保存的Truck类实例中,给定程序集名称InvokeTester、类名Truck、方法名GetDescription,调用GetDescription方法。代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace InvokeTester { class Program { static void Main(string[] args) { try { string dllName = "InvokeTester"; //程序集名 string className = "InvokeTester.Truck"; //类全名 string methodName = "GetDescription"; //方法名 //调用对象的指定方法 Vehicle vehicle = new Truck("大象牌", "DX001", "起重机"); Assembly assembly = Assembly.Load(dllName); if (assembly != null) { Type type = assembly.GetType(className); if (type != null) { MethodInfo methodInfo = type.GetMethod(methodName); if (methodInfo != null) { string desc = methodInfo.Invoke(vehicle, null).ToString(); Console.WriteLine(desc); } } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.Read(); } } }
这段代码的执行结果如下:
使用本方法还需要注意一点:
如果被调用的方法在不同的程序集内,请确保这个程序集只生成一个DLL。如果这个程序集生成了多个DLL(可能因为多个生成目标地址不用的程序集都依赖于这个程序集,导致这个程序集的DLL散落在多处),那么在调用MethodInfo类的Invoke函数时可能会报错,异常信息为:“对象与目标类型不匹配”。
END