10分钟教你理解反射

什么是反射?
反射反射,程序员的快乐,在.Net领域程序设计中,反射是无处不在的,MVC、ASP.Net、各种ORM、IOC、AOP几乎所有的框架都离不开反射。反编译工具使用的底层技术用的不是反射,是一种逆向工程。

反射(Reflection、System.Reflection),是.Net Framework提供的一个帮助类库,可以读取并使用Metadata中描述的数据信息。元数据(Metadata),描述了dll/exe里面的各种信息,又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。

反射的优缺点:
优点:动态—在不破坏原有程序的情况下,可对程序进行良好的扩展。Eg:我们有这样一需求,项目在最初的时候用的是Mysql数据库,由于项目情况变化需要更换成SqlServer数据库。面对这种项目的需求,传统的解决方法是在项目中添加新的SqlServer数据库访问代码,将数据库访问实现层更改为SqlServer,最后编译源代码并重新发布。

传统解决方法示例伪代码如下:

1 IDBHelper iDBHelper = new MySqlHelper();
2 IDBHelper iDBHelper = new SqlServerHelper();
3 iDBHelper.Query();
使用反射的示例代码:

1 namespace ReflectionDemo
2 {
3 ///
4 /// 反射工厂
5 ///
6 public class SimpleFactory
7 {
8 //读取配置文件
9 private static string IDBHelperConfig = ConfigurationManager.AppSettings[“IDBHelperConfig”];
10 //获取需要加载的dll名称
11 private static string DllName = IDBHelperConfig.Split(’,’)[0];
12 //获取需要的类型名称
13 private static string TypeName = IDBHelperConfig.Split(’,’)[1];
14 ///
15 /// 通过反射动态加载与类型名称相匹配的实例
16 ///
17 ///
18 public static IDBHelper CreateInstance()
19 {
20 Assembly assembly = Assembly.Load(DllName);
21 Type type = assembly.GetType(TypeName);
22 object oDBHelper = Activator.CreateInstance(type);
23 IDBHelper iDBHelper = oDBHelper as IDBHelper;
24 return iDBHelper;
25 }
26 }
27 }

IDBHelper iDBHelper = SimpleFactory.CreateInstance(); iDBHelper.Query(); 通过反射实现了程序的可配置,通过修改配置文件就可以自动切换实现类,实现类必须是事先已有的, 没有将实现类固定,而是通过配置文件执行,通过反射创建的。可扩展:完全不修改原有代码,只是增加新的实现、修改配置文件,就可以支持新功能。这就是反射的动态特性。

缺点:使用麻烦、避开编译器检查导致运程序行时异常变多、性能问题。

通过反射调用构造函数

1 namespace SqlServerDb
2 {
3
4 ///
5 /// 反射测试类
6 ///
7 public class ReflectionTest
8 {
9 #region Identity
10 ///
11 /// 无参构造函数
12 ///
13 public ReflectionTest()
14 {
15 Console.WriteLine(“这里是{0}无参数构造函数”, this.GetType());
16 }
17
18 ///
19 /// 带参数构造函数
20 ///
21 ///
22 public ReflectionTest(string name)
23 {
24 Console.WriteLine(“这里是{0} 有参数【string】构造函数”, this.GetType());
25 }
26
27 public ReflectionTest(int id)
28 {
29 Console.WriteLine(“这里是{0} 有参数【int】构造函数”, this.GetType());
30 }
31 #endregion
32
33 #region Method
34 ///
35 /// 无参方法
36 ///
37 public void Show1()
38 {
39 Console.WriteLine(“这里是{0}的Show1”, this.GetType());
40 }
41 ///
42 /// 有参数方法
43 ///
44 ///
45 public void Show2(int id)
46 {
47
48 Console.WriteLine(“这里是{0}的Show2”, this.GetType());
49 }
50 ///
51 /// 重载方法之一
52 ///
53 ///
54 ///
55 public void Show3(int id, string name)
56 {
57 Console.WriteLine(“这里是{0}的Show3”, this.GetType());
58 }
59 ///
60 /// 重载方法之二
61 ///
62 ///
63 ///
64 public void Show3(string name, int id)
65 {
66 Console.WriteLine(“这里是{0}的Show3_2”, this.GetType());
67 }
68 ///
69 /// 重载方法之三
70 ///
71 ///
72 public void Show3(int id)
73 {
74 Console.WriteLine(“这里是{0}的Show3_3”, this.GetType());
75 }
76 ///
77 /// 重载方法之四
78 ///
79 ///
80 public void Show3(string name)
81 {
82 Console.WriteLine(“这里是{0}的Show3_4”, this.GetType());
83 }
84
85 ///
86 /// 重载方法之五
87 ///
88 public void Show3()
89 {
90 Console.WriteLine(“这里是{0}的Show3_1”, this.GetType());
91 }
92
93 ///
94 /// 私有方法
95 ///
96 ///
97 private void Show4(string name)
98 {
99 Console.WriteLine(“这里是{0}的Show4”, this.GetType());
100 }
101
102 ///
103 /// 静态方法
104 ///
105 ///
106 public static void Show5(string name)
107 {
108 Console.WriteLine(“这里是{0}的Show5”, typeof(ReflectionTest));
109 }
110 #endregion
111 }
112 }

1 Assembly assembly = Assembly.Load(“SqlServerDb”);
2 Type type = assembly.GetType(“SqlServerDb.ReflectionTest”);
3 foreach (ConstructorInfo ctor in type.GetConstructors())
4 {
5 Console.WriteLine(KaTeX parse error: Expected '}', got 'EOF' at end of input: …sole.WriteLine(“ParameterType:{parameter.ParameterType},parameterName: {parameter.Name}”);
9 }
10 }
11 object oTest1 = Activator.CreateInstance(type);
12 object oTest2 = Activator.CreateInstance(type, new object[] { 123 });
13 object oTest3 = Activator.CreateInstance(type, new object[] { “陌殇” });

反射破坏单例
1 //反射破坏单例—就是反射调用私有构造函数
2 Assembly assembly = Assembly.Load(“SqlServerDb”);
3 Type type = assembly.GetType(“SqlServerDb.Singleton”);
4 Singleton singletonA = (Singleton)Activator.CreateInstance(type, true);
5 Singleton singletonB = (Singleton)Activator.CreateInstance(type, true);
6 Console.WriteLine($"{object.ReferenceEquals(singletonA, singletonB)}");
反射调用泛型类

namespace SqlServerDb
{

/// <summary>
/// 泛型测试类
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="W"></typeparam>
/// <typeparam name="X"></typeparam>
public class GenericClass<T, W, X>
{
    public GenericClass()
    {
        Console.WriteLine("GenericClass<T, W, X>的构造函数被调用了");
    }


    public void Show(T t, W w, X x)
    {
        Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name);
    }
}

/// <summary>
/// 泛型测试方法
/// </summary>
public class GenericMethod
{

    public GenericMethod()
    {
        Console.WriteLine("GenericMethod类的构造函数被调用了。");
    }

    public void Show<T, W, X>(T t, W w, X x)
    {
        Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name);
    }

    
}

public class GenericDouble<T>
{
    public void Show<W, X>(T t, W w, X x)
    {
        Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name);
    }
}

}

1 Assembly assembly = Assembly.Load(“SqlServerDb”);
2 Type type = assembly.GetType(“SqlServerDb.GenericClass`3”);
3 GenericClass<string, int, DateTime> genericClass = new GenericClass<string, int, DateTime>();
4 //genericClass.Show(“12”, 1, DateTime.Now);
5 //object oGeneric = Activator.CreateInstance(type);
6 Type typeMake = type.MakeGenericType(new Type[] { typeof(string), typeof(int), typeof(DateTime) });
7 object oGeneric = Activator.CreateInstance(typeMake);

反射调用泛型方法
Assembly assembly = Assembly.Load(“SqlServerDb”);
Type type = assembly.GetType(“SqlServerDb.GenericMethod”);
object oGeneric = Activator.CreateInstance(type);
如果反射创建对象之后,知道方法名称,怎么样不做类型转换,直接调用方法?

1 2 Assembly assembly = Assembly.Load(“SqlServerDb”);
3 Type type = assembly.GetType(“SqlServerDb.ReflectionTest”);
4 object oTest = Activator.CreateInstance(type);
5 foreach (var method in type.GetMethods())
6 {
7 Console.WriteLine(method.Name);
8 foreach (var parameter in method.GetParameters())
9 {
10 Console.WriteLine($"{parameter.Name} {parameter.ParameterType}");
11 }
12 }
13 {
14 ReflectionTest reflection = new ReflectionTest();
15 reflection.Show1();
16 }
17 {
18 MethodInfo method = type.GetMethod(“Show1”);
19 //if()
20 method.Invoke(oTest, null);
21 }
22 {
23 MethodInfo method = type.GetMethod(“Show2”);
24 method.Invoke(oTest, new object[] { 123 });
25 }
26 {
27 MethodInfo method = type.GetMethod(“Show3”, new Type[] { });
28 method.Invoke(oTest, null);
29 }
30 {
31 MethodInfo method = type.GetMethod(“Show3”, new Type[] { typeof(int) });
32 method.Invoke(oTest, new object[] { 123 });
33 }
34 {
35 MethodInfo method = type.GetMethod(“Show3”, new Type[] { typeof(string) });
36 method.Invoke(oTest, new object[] { “一生为你” });
37 }
38 {
39 MethodInfo method = type.GetMethod(“Show3”, new Type[] { typeof(int), typeof(string) });
40 method.Invoke(oTest, new object[] { 234, “心欲无痕” });
41 }
42 {
43 MethodInfo method = type.GetMethod(“Show3”, new Type[] { typeof(string), typeof(int) });
44 method.Invoke(oTest, new object[] { “PHS”, 345 });
45 }
46 {
47 MethodInfo method = type.GetMethod(“Show5”);
48 method.Invoke(oTest, new object[] { “张中魁” });//静态方法实例可以要
49 }
50 {
51 MethodInfo method = type.GetMethod(“Show5”);
52 method.Invoke(null, new object[] { “张中魁” });//静态方法实例也可以不要
53 }

反射调用私有方法

1 {
2 //调用私有方法
3 Console.WriteLine("&&&&&&&&&&&&&&&&&&&&私有方法&&&&&&&&&&&&&&&&&&&");
4 Assembly assembly = Assembly.Load(“SqlServerDb”);
5 Type type = assembly.GetType(“SqlServerDb.ReflectionTest”);
6 object oTest = Activator.CreateInstance(type);
7 var method = type.GetMethod(“Show4”, BindingFlags.Instance | BindingFlags.NonPublic);
8 method.Invoke(oTest, new object[] { “我是老王” });
9 }

反射调用泛型方法

            Assembly assembly = Assembly.Load("SqlServerDb");
            Type type = assembly.GetType("SqlServerDb.GenericMethod");
            object oGeneric = Activator.CreateInstance(type);
            foreach (var item in type.GetMethods())
            {
                Console.WriteLine(item.Name);
            }
            MethodInfo method = type.GetMethod("Show");
            //指定泛型方法的参数类型
            var methodNew = method.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
            object oReturn = methodNew.Invoke(oGeneric, new object[] { 123, "董小姐", DateTime.Now });

反射调用泛型方法加泛型类
1 Assembly assembly = Assembly.Load(“SqlServerDb”);
2 //在获取类型的同时通过MakeGenericType指定泛型的参数类型
3 Type type = assembly.GetType(“SqlServerDb.GenericDouble`1”).MakeGenericType(typeof(int));
4 object oObject = Activator.CreateInstance(type);
5 MethodInfo method = type.GetMethod(“Show”).MakeGenericMethod(typeof(string), typeof(DateTime));
6 method.Invoke(oObject, new object[] { 345, “感谢有梦”, DateTime.Now });

深圳网站建设https://www.sz886.com

猜你喜欢

转载自blog.csdn.net/chenmh12/article/details/91411439