C# 反射之调用方法谈
反射的定义
反射提供了描述程序集、模块和类型的对象(Type 类型)。 可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。 如果代码中使用了特性,可以利用反射来访问它们。------摘自MSDN
自我理解
看到反射二字,自然而然的会想到,小时候拿着一面镜子,反射阳光玩。其实
反射就好比一面镜子,通过它我们能在不显示引用程序集的情况下,一窥程序集内的“风景”。
利用好反射这把利器,我们在开发中就能体会到荀老夫子所言的,君子性非异也,善假于物也
本文主要包括以下四节:
通过反射调用类的构造函数(有参/无参)
通过反射调用类的静态方法(有参/无参)
通过反射调用类的非静态方法(有参/无参)
通过反射调用类的含有ref参数的方法
代码示例:
1 namespace TestDLL 2 { 3 using System.Linq; 4 5 public class TestClass 6 { 7 private int _priValue; 8 9 //无参构造函数 10 public TestClass() 11 { 12 this._priValue = 9; 13 } 14 15 //有参构造函数 16 public TestClass(int i) 17 { 18 this._priValue = i; 19 } 20 21 //无参方法 22 public int Add() 23 { 24 return ++this._priValue; 25 } 26 27 //ref参数的方法 28 public void Exchange(ref int a, ref int b) 29 { 30 int temp = b; 31 b = a; 32 a = temp; 33 } 34 35 // 静态有参方法 36 public static string SayHi(string name) 37 { 38 return "Hi~ " + name; 39 } 40 41 public static int AddValue(int[] objsInts) 42 { 43 int temp = 0; 44 if (objsInts != null) 45 { 46 temp += objsInts.Sum(); 47 } 48 return temp; 49 } 50 } 51 }
通过反射调用代码示例:
static void Main(string[] args) { //加载程序集(dll文件地址),使用Assembly类 Assembly testDll = Assembly.LoadFile(Environment.CurrentDirectory + "\\TestDLL.dll"); //获取类型,参数(名称空间+类) Type testClass = testDll.GetType("TestDLL.TestClass"); //创建实例 var instance = testDll.CreateInstance("TestDLL.TestClass"); //调用无参构造函数 ConstructorInfo noParamConstructor = testClass.GetConstructor(Type.EmptyTypes); object testClassObject = noParamConstructor.Invoke(new object[] { }); //调用有参构造函数 ConstructorInfo paramConstructor = testClass.GetConstructor(new Type[] { Type.GetType("System.Int32") }); object testClassObject2 = paramConstructor.Invoke(new object[] { 2 }); #region 调用非静态方法 MethodInfo addMethod = testClass.GetMethod("Add"); object addValue = addMethod.Invoke(instance, new object[] { }); #endregion #region 调用静态有参方法 MethodInfo sayHiMethod = testClass.GetMethod("SayHi"); object sayHi = sayHiMethod.Invoke(null, new object[] { "jason" }); #endregion #region 调用含有ref参数的方法 MethodInfo exchange = testClass.GetMethod("Exchange"); var objs = new object[2]; objs[0] = 5; objs[1] = 6; Console.WriteLine("objs[0]={0}\nobjs[1]={1}", objs[0], objs[1]); object retValue = exchange.Invoke(instance, objs); #endregion #region 调用参数为数组的方法 MethodInfo addValueInfo = testClass.GetMethod("AddValue"); var ints = new int[] {1, 2, 3, 4, 5}; object obj = addValueInfo.Invoke(null, new object[] {ints}); #endregion Console.WriteLine("MethodInfo.Invoke() Example\n"); Console.WriteLine("TestClass.Add() returned: {0}", addValue); Console.WriteLine("TestClass.SayHi() returned:{0}", sayHi); Console.WriteLine("TestClass.Exchange(ref int a,ref int b) returned:{0}", retValue); Console.WriteLine("objs[0]={0}\nobjs[1]={1}", objs[0], objs[1]); Console.WriteLine("AddValue(int[] objsInts) result:{0}", obj); }
在此对代码中红色加粗的方法做注(摘自MSDN):
MethodBase.Invoke 方法 (Object, Object[])
使用指定的参数调用当前实例所表示的方法或构造函数。
语法
public Object Invoke(
Object obj,
Object[] parameters
)
参数
obj
类型:System.Object
对其调用方法或构造函数的对象。 如果方法是静态的,则忽略此参数。 如果构造函数是静态的,则此参数必须为 null 或定义该构造函数的类的实例。
若要使用其 MethodInfo 对象来调用静态方法,请将 null 传递给 obj。
parameters
类型:System.Object[]
调用的方法或构造函数的参数列表。 这是一个对象数组,这些对象与要调用的方法或构造函数的参数具有相同的数量、顺序和类型。 如果没有任何参数,则 parameters 应为 null。
如果此实例所表示的方法或构造函数采用 ref 参数(在 Visual Basic 中为 ByRef),使用此函数调用该方法或构造函数时,该参数不需要任何特殊属性。 如果此数组中的对象未用值来显式初始化,则该对象将包含该对象类型的默认值。 对于引用类型的元素,该值为 null。 对于值类型的元素,该值为 0、0.0 或 false,具体取决于特定的元素类型。
返回值
类型:System.Object
一个对象,包含被调用方法的返回值,如果调用的是构造函数,则为 null。