一个例子:C#语言使用反射调用指定类内的函数

jopen 8年前

今天研究了一下,当指定程序集、类全名、方法名时,给定一个该类的实例,如何调用该实例中指定的方法。

这个功能的背景是这样的:

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

来自: http://my.oschina.net/Tsybius2014/blog/602117