-
C#教程之浅谈.NET中的反射(2)
试听地址 https://www.xin3721.com/eschool/CSharpxin3721/
{ 21 //方法的参数类型名称 22 Console.Write(pi[i].ParameterType.Name); 23 //方法的参数名 24 Console.Write($" {pi[i].Name}"); 25 if (i+1<pi.Length) 26 { 27 Console.Write(", "); 28 } 29 } 30 31 Console.Write(")"); 32 Console.Write("\r\n"); 33 Console.WriteLine("--------------------------"); 34 } 35 Console.ReadKey(); 36 } 37 } 38 39 class MyClass 40 { 41 private int x; 42 private int y; 43 44 public MyClass() 45 { 46 x = 1; 47 y = 1; 48 } 49 50 public int Sum() 51 { 52 return x + y; 53 } 54 55 public bool IsBetween(int i) 56 { 57 if (x < i && i < y) 58 { 59 return true; 60 } 61 62 return false; 63 } 64 65 public void Set(int a, int b) 66 { 67 x = a; 68 y = b; 69 } 70 71 public void Set(double a, double b) 72 { 73 x = (int)a; 74 y = (int)b; 75 } 76 77 public void Show() 78 { 79 System.Console.WriteLine($"x:{x},y:{y}"); 80 } 81 }
输出结果:
上面例子可以看出,只显示了MyClass类显示定义的方法,private int Sum() 也不显示了
六、使用反射调用方法
上面我们通过反射获取到了类中的所有信息,下面我们就再使用反射调用反射获取到的方法。要调用反射获取到的方法,则需要在MethodInfo实例上调用Invoke()方法,Invoke()的使用,在下面例子中演示说明:
下面例子是先通过反射获取到要调用的方法,然后使用Invoke()方法,调用获取到的指定方法:
1 class Program
2 {
3 static void Main()
4 {
5 //获取描述MyClass类型的Type对象
6 Type t = typeof(MyClass);
7 MyClass reflectObj = new MyClass();
8 reflectObj.Show();
9 //不获取继承方法,为实例方法,·为公用的
10 MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
11 foreach (var methodInfo in mi)
12 {
13
14 //获取方法阐述列表并保存在ParameterInfo对象组中
15 ParameterInfo[] pi = methodInfo.GetParameters();
16 if (methodInfo.Name.Equals("Set", StringComparison.Ordinal) && pi[0].ParameterType == typeof(int))
17 {
18 object[] args = new object[2];
19 args[0] = 9;
20 args[1] = 10;
21 methodInfo.Invoke(reflectObj,args);
22 }
23 }
24 Console.ReadKey();
25 }
26 }
27
28 class MyClass
29 {
30 private int x;
31 private int y;
32
33 public MyClass()
34 {
35 x = 1;
36 y = 1;
37 }
38
39 public int Sum()
40 {
41 return x + y;
42 }
43
44 public bool IsBetween(int i)
45 {
46 if (x < i && i < y)
47 {
48 return true;
49 }
50
51 return false;
52 }
53
54 public void Set(int a, int b)
55 {
56 x = a;
57 y = b;
58 Show();
59 }
60
61 private void Set(double a, double b)
62 {
63 x = (int)a;
64 y = (int)b;
65 }
66
67 public void Show()
68 {
69 System.Console.WriteLine($"x:{x},y:{y}");
70 }
71 }
获取Type对象的构造函数
这个之前的阐述中,由于MyClass类型的对象都是显示创建的,因此使用反射技术调用MyClass类中的方法是没有任何优势的,还不如以普通方式调用方便简单呢,但是,如果对象是在运行时动态创建的,反射功能的优势就会显现出来。在这种情况下,要先获取一个构造函数列表,然后调用列表中的某个构造函数,创建一个该类型的实例,通过这种机制,可以在运行时实例化任意类型的对象,而不必在声明语句中指定类型。
示例代码如下:
1 class Program
2 {
3 static void Main()
4 {
5 //获取描述MyClass类型的Type对象
6 Type t = typeof(MyClass);
7 int val;
8 //使用这个方法获取构造函数列表
9 ConstructorInfo[] ci = t.GetConstructors();
10 int x;
11 for (x = 0; x < ci.Length; x++)
12 {
13 //获取当构造参数列表
14 ParameterInfo[] pi = ci[x].GetParameters();
15 if (pi.Length == 2)
16 {
17 //如果当前构造函数有2个参数,则跳出循环
18 break;
19 }
20 }
21
22 if (x == ci.Length)
23 {
24 return;
25 }
26 object[] consArgs = new object[2];
27 consArgs[0] = 10;
28 consArgs[1] = 20;
29 //实例化一个这个构造函数有连个参数的类型对象,如果参数为空,则为null
30
31 object reflectOb = ci[x].Invoke(consArgs);
32
33 MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
34 foreach (var methodInfo in mi)
35 {
36 if (methodInfo.Name.Equals("Sum", StringComparison.Ordinal))
37 {
38 val = (int)methodInfo.Invoke(reflectOb, null);
39 Console.WriteLine($"Sum is {val}");
40 }
41 }
42 Console.ReadKey();
43 }
44 }
45
46 class MyClass
47 {
48 private int x;
49 private int y;
50
51 public MyClass(int i)
52 {
53 x = y + i;
54 }
55
56 public MyClass(int i, int j)
57 {
58 x = i;
59 y = j;
60 }
61
62 public int Sum()
63 {
64 return x + y;
65 }
66 }
输出结果:
七、从程序集获得类型
在这之前的阐述中可以看出一个类型的所有信息都能够通过反射得到,但是MyClass类型本身,我们却没有做到获取,虽然前面的阐述实例,可以动态确定MyClass类的信息,但是他们都是基于以下事实:预先知道类型名称,并且在typeof与剧中使用它获得Type对象。尽管这种方式可能在很多情况下都管用,但是要发挥反射的全部功能,我们还需要分析反射程序集的内容来动态确定程序的可用类型。
借助Reflection API,可以加载程序集,获取它的相关信息并创建其公共可用类型的实例,通过这种机制,程序能够搜索其环境,利用潜在的功能,而无需再编译期间显示的定义他们,这是一个非常有效且令人兴奋的概念。为了说明如何获取程序集中的类型,我创建了两个文件,第一个文件定义一组类,第二个文件则反射各个类型的信息。代码效果如下:
1、这下面代码编译生成MyTest2_C.exe文件
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Console.WriteLine("Hello word !");
6 Console.ReadKey();
7 }
8 }
9
10 class MyClass
11 {
12 private int x;
13 private int y;
14
15 public MyClass(int i)
16 {
17 x = y + i;
18 }
19
20 public MyClass(int i, int j)
21 {
22 x = i;
23 y = j;
24 }
25
26 public int Sum()
27 {
28 return x + y;
29 }
30 }
2、这下面的代码时获取上面生成程序集的
1 class Program
2 {
3 static void Main()
4 {
5 //加载指定的程序集
6 Assembly asm = Assembly.LoadFrom(@"E:\自己的\MyTest\MyTest2_C\bin\Debug\MyTest2_C.exe");
7 //获取程序集中的所有类型列表
8 Type[] allType = asm.GetTypes();
9 foreach (var type in allType)
10 {
11 //打印出类型名称
12 Console.WriteLine(type.Name);
13 }
14
15 Console.ReadKey();
16 }
17 }
输出结果:
上面获取到了程序集中的类型,如果像操作程序集类型中的方法,则跟前面我们表述的方法一样操作即可。
好了,.Net反射我们就介绍到这里啦~