• 第六节:反射(几种写法、好处和弊端、利用反射实现IOC)


    一. 加载dll,读取相关信息

    1. 加载程序集的三种方式

     调用Assembly类下的三个方法:Load、LoadFile、LoadFrom。

    1        //1.1 Load方法:动态默认加载当前路径下的(bin)下的dll文件,不需要后缀
    2             Assembly assembly = Assembly.Load("DB.SQLServer");
    3             //1.2 LoadFile方法:程序集的绝对路径
    4             Assembly assembly2 = Assembly.LoadFile(@"D:我的框架之路DotNet体系2-DotNet进阶2-反射1-codeReflectioninDebugDB.SQLServer.dll");
    5             //1.3 LoadFrom方法:可以是当前路径(需要写上后缀.dll),也可以是绝对路径
    6             Assembly assembly3 = Assembly.LoadFrom("DB.SQLServer.dll");

    2. 获取程序集中所有的类

     通过方法GetTypes来实现。

    1 Assembly assembly = Assembly.Load("DB.SQLServer");
    2 Type[] t1 = assembly.GetTypes();

        通过方法GetType("类名全写")来实现获取单个类(DBHelper)。

    1 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");

    3. 获取类中的所有构造函数

      通过方法GetConstructors来实现。

    1 //1.加载程序集
    2 Assembly assembly = Assembly.Load("DB.SQLServer");
    3 //2.获取程序集中的特定类
    4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
    5 //3.获取特定类中的所有构造函数
    6 ConstructorInfo[] cInfor = tItem.GetConstructors();

    4. 获取类中的所有属性

      通过方法GetProperties来实现。

    1  //1.加载程序集
    2 Assembly assembly = Assembly.Load("DB.SQLServer");
    3 //2.获取程序集中的特定类
    4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
    5 //3.获取特定类中的所有属性
    6 PropertyInfo[] propertyInfo = tItem.GetProperties();

    5. 获取类中的所有方法

       通过方法GetMethods来实现。

     //1.加载程序集
    Assembly assembly = Assembly.Load("DB.SQLServer");
    //2.获取程序集中的特定类
    Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
    //3.获取特定类中的所有方法
    MethodInfo[] methordInfo = tItem.GetMethods();

    6. 获取类中的所有接口

      通过方法GetInterfaces来实现。

    1 //1.加载程序集
    2 Assembly assembly = Assembly.Load("DB.SQLServer");
    3 //2.获取程序集中的特定类
    4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
    5 //3.获取特定类中的所有接口
    6 Type[] type = tItem.GetInterfaces();

    二. 反射创建对象

    1. 反射创建对象

     通过Activator.CreateInstance()方法来创建对象

    1.1 ReflectionTest类的代码

     1  public class ReflectionTest
     2     {
     3         public int Id { get; set; }
     4         public string Name { get; set; }
     5 
     6         public string Field = null;
     7         public static string FieldStatic = null;
     8 
     9 
    10         #region 构造函数
    11         public ReflectionTest()
    12         {
    13             Console.WriteLine("这里是{0}无参数构造函数", this.GetType());
    14         }
    15 
    16         public ReflectionTest(string name)
    17         {
    18             Console.WriteLine("这里是{0} 有1个参数构造函数", this.GetType());
    19         }
    20 
    21         public ReflectionTest(int id, string name)
    22         {
    23             Console.WriteLine("这里是{0} 有2个参数构造函数", this.GetType());
    24         }
    25         #endregion
    26 
    27         public void Show1()
    28         {
    29             Console.WriteLine("这里是{0}的Show1", this.GetType());
    30         }
    31 
    32         public void Show2(int id)
    33         {
    34 
    35             Console.WriteLine("这里是{0}的Show2", this.GetType());
    36         }
    37 
    38         public static void ShowStatic(string name)
    39         {
    40             Console.WriteLine("这里是{0}的ShowStatic", typeof(ReflectionTest));
    41         }
    42 
    43         public void Show3()
    44         {
    45             Console.WriteLine("这里是{0}的Show3_1", this.GetType());
    46         }
    47 
    48         public void Show3(int id, string name)
    49         {
    50             Console.WriteLine("这里是{0}的Show3", this.GetType());
    51         }
    52 
    53         public void Show3(string name, int id)
    54         {
    55             Console.WriteLine("这里是{0}的Show3_2", this.GetType());
    56         }
    57 
    58         public void Show3(int id)
    59         {
    60 
    61             Console.WriteLine("这里是{0}的Show3_3", this.GetType());
    62         }
    63 
    64         public void Show3(string name)
    65         {
    66 
    67             Console.WriteLine("这里是{0}的Show3_4", this.GetType());
    68         }
    69 
    70         private void Show4(string name)
    71         {
    72             Console.WriteLine("这里是{0}的Show4", this.GetType());
    73         }
    74         public void ShowGeneric<T>(T name)
    75         {
    76             Console.WriteLine("这里是{0}的ShowStatic  T={1}", this.GetType(), typeof(T));
    77         }
    78     }

    1.2 反射创建对象的代码

     1 //1.加载程序集
     2 Assembly assembly = Assembly.Load("DB.SQLServer");
     3 //2.获取程序集中的特定类
     4 Type tItem = assembly.GetType("DB.SQLServer.ReflectionTest");
     5  //3.1 无参构造函数
     6 Activator.CreateInstance(tItem);
     7  //3.2 一个参数的构造函数
     8 Activator.CreateInstance(tItem ,"1");
     9 //3.3 两个参数的构造函数
    10  Activator.CreateInstance(tItem , 1,"2");

    2. 反射破坏单例,调用私有构造函数

       单例代码

     1  public sealed class Singleton
     2     {
     3         private Singleton()
     4         {
     5             Console.WriteLine("初始化一次");
     6         }
     7 
     8         private static Singleton Instance = new Singleton();
     9 
    10         public static Singleton CreateInstance()
    11         {
    12             return Instance;
    13         }
    14     }

       破坏单例,调用私有构造函数代码

    1 //1.加载程序集
    2 Assembly assembly = Assembly.Load("DB.SQLServer");
    3 //2. 获取单例类
    4 Type tc3 = assembly .GetType("DB.SQLServer.Singleton");
    5 //3. 创建对象
    6 Activator.CreateInstance(tc3, true);

    3. 反射创建泛型(扩展)

    1  //1.加载程序集
    2 Assembly assembly = Assembly.Load("DB.SQLServer");
    3  //2. 获取单例类
    4 Type tc4 = assembly4.GetType("DB.SQLServer.GenericClass`1");
    5 tc4 = tc4.MakeGenericType(typeof(int));
    6 Activator.CreateInstance(tc4);

    三. IOC(反射+简单工厂+配置文件)

       背景:有三套相同的数据库,分别是SQLServer、MySQL、Oracle数据库,要求可以分别连接这三个不同的数据库,并且发布后,可以在不重新发布的情况下,切换连接数据库。

       对应上述背景,建立相应的解决方案,目录如下,并介绍介绍几种传统的解决方案

    方案一:在Reflection中直接添加对DB.SQLServer的引用

    1  Console.WriteLine("------------------------------------1. 传统方式调用DBHelper中的Query方法--------------------------------------");
    2  //1.传统的方式调用(需要对 DB.SQLServer添加引用)
    3  DBHelper db1 = new DBHelper("123");
    4  db1.Query();

    方案二:在Reflection中直接添加对DB.SQLServer、DB.Interface的引用

    1   Console.WriteLine("------------------------------------2. 接口的方式调用--------------------------------------");
    2   //2. 接口的方式调用(只需要引用接口的程序集即可)
    3   IDBHelper idb1 = new DBHelper("123");
    4   idb1.Query();

    点评:以上两种方案实质上都是通过对相应的实现类添加引用,new出来对象,然后调用方法来实现,没法发布后动态修改数据库。

     方案三:通过反射来创建对象,只需要添加对DB.Interface的引用即可,但需要把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目录改成Reflection程序下

    1  Console.WriteLine("------------------------------------3. 反射的方式创建对象--------------------------------------");
    2  //3. 反射的方式创建对象(不需要直接添加对其引用,只需要把相应的程序生成路径改成Reflection中即可)
    3  Assembly assembly4 = Assembly.Load("DB.SQLServer");
    4  Type tc = assembly4.GetType("DB.SQLServer.DBHelper");
    5  //object myDbHelper = Activator.CreateInstance(tc, "123"); //调用带参数的构造函数
    6  object myDbHelper = Activator.CreateInstance(tc);     //默认调用无参构造函数
    7  IDBHelper idb2 = (IDBHelper)myDbHelper;
    8  idb2.Query();

    点评:该方案只需要对接口添加引用,符合了面向接口编程的思想,但是发布后在不修改代码的情况下,不能切换数据库。

    方案四:IOC(反射+简单工厂+配置文件),需要添加对DB.Interface的引用,并且把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目录改成Reflection程序下

    配置文件:

     1   <appSettings>
     2     <!--直接修改配置文件,可以修改数据库连接牛逼,可以直接切换 oracle 、mysql数据库,发布后可以直接通过改配置文件,切换数据库,代码什么也不用改,体会:反射+面向接口编程-->
     3     <!--前提:相应的DBHelper类必须满足接口约束,需要把Oracle或MySql的dll文件拷贝到Reflection中的bin文件中  -->
     4     <!--SQLServer改为:         -->
     5     <!--<add key="IDBHelper-dllName" value="DB.SQLServer"/>
     6     <add key="IDBHelper-className" value="DB.SQLServer.DBHelper"/>-->
     7     <!--Oracle改为:         -->
     8     <!--<add key="IDBHelper-dllName" value="DB.Oracle"/>
     9     <add key="IDBHelper-className" value="DB.Oracle.DBHelper"/>-->
    10     <!--MySql改为:         -->
    11     <add key="IDBHelper-dllName" value="DB.MySql"/>
    12     <add key="IDBHelper-className" value="DB.MySql.DBHelper"/>
    13   </appSettings>

    简单工厂:

     1 /// <summary>
     2     /// 简单工厂,创建对象
     3     /// </summary>
     4     public class SimpleFactory
     5     {
     6         private static string IDBHelperdllName = ConfigurationManager.AppSettings["IDBHelper-dllName"];
     7         private static string IDBHelperClassName = ConfigurationManager.AppSettings["IDBHelper-className"];
     8 
     9         public static IDBHelper CreateDBHelper()
    10         {
    11             Assembly assembly = Assembly.Load(IDBHelperdllName);
    12             Type type = assembly.GetType(IDBHelperClassName);
    13             object obj = Activator.CreateInstance(type);
    14             return (IDBHelper)obj;
    15         }
    16 
    17     }

    调用:

    1   Console.WriteLine("------------------------------------4. IOC(反射+简单工厂+配置文件)--------------------------------------");
    2   //4. IOC(反射+简单工厂+配置文件)(不需要直接添加对其引用,只需要把相应的程序生成路径改成Reflection中即可)
    3   IDBHelper idb3 = SimpleFactory.CreateDBHelper();
    4   idb3.Query();

    四. 反射调用实例方法、静态方法、重载方法

     1         //2. 实例方法、静态方法、重载方法的调用
     2             {
     3                 object obj = Activator.CreateInstance(tc5);
     4                 Console.WriteLine("---------------------------------2.1 调用无参、有参的实例方法-------------------------------------");
     5                 //2.1 调用无参、有参的实例方法
     6                 {
     7                     MethodInfo methord = tc5.GetMethod("Show1");
     8                     methord.Invoke(obj, null);
     9                 }
    10                 {
    11                     MethodInfo methord = tc5.GetMethod("Show2");
    12                     methord.Invoke(obj, new object[]{11});
    13                 }
    14 
    15                 Console.WriteLine("---------------------------------2.2 调用静态方法-------------------------------------");
    16                 //2.2 调用静态方法
    17                 {
    18                     MethodInfo methord = tc5.GetMethod("ShowStatic");
    19                     methord.Invoke(obj, new object[] { "ShowStatic1234" });
    20                 }
    21 
    22                 Console.WriteLine("---------------------------------2.3 调用重载方法(需要在创建方法的时候,把类型传进去)-------------------------------------");
    23                 //2.3 调用重载方法(需要在创建方法的时候,把类型传进去)
    24                 {
    25                     MethodInfo methord = tc5.GetMethod("Show3", new Type[] { });
    26                     methord.Invoke(obj, null);
    27                 }
    28                 {
    29                     MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int)});
    30                     methord.Invoke(obj, new object[] { 11 });
    31                 }
    32                 {
    33                     MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string) });
    34                     methord.Invoke(obj, new object[] { "11" });
    35                 }
    36                 {
    37                     MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });
    38                     methord.Invoke(obj, new object[] { 11 ,"11"});
    39                 }
    40                 {
    41                     MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
    42                     methord.Invoke(obj, new object[] { "11",11 });
    43                 }
    44 
    45                 Console.WriteLine("---------------------------------2.4 调用私有方法-------------------------------------");
    46                 //2.4 调用私有方法
    47                 {
    48                     MethodInfo methord = tc5.GetMethod("Show4", BindingFlags.Instance|BindingFlags.NonPublic);
    49                     methord.Invoke(obj, new object[] { "11" });
    50                 }
    51                 Console.WriteLine("---------------------------------2.5 调用泛型方法-------------------------------------");
    52                 //2.5 调用泛型方法
    53                 {
    54                     MethodInfo methord = tc5.GetMethod("ShowGeneric");
    55                     methord = methord.MakeGenericMethod(typeof(string));
    56                     methord.Invoke(obj, new object[] { "123" });
    57                 }
    58 
    59             }

    五. 反射字段和属性,获取值和设置值

      {
                    //实例化对象
                    ReflectionTest rTest = new ReflectionTest();
                    //反射
                    Assembly assembly5 = Assembly.Load("DB.SQLServer");
                    Type type5 = assembly5.GetType("DB.SQLServer.ReflectionTest");
                    object object5 = Activator.CreateInstance(type5);
                    //1.获取类的所有属性
                    Console.WriteLine("------------------------------------1.获取类的属性--------------------------------------");
                    var pInfor= type5.GetProperties();
                    foreach (var item in pInfor)
                    {
                        Console.WriteLine(item.Name);
                        if (item.Name.Equals("Id"))
                        {
                            item.SetValue(object5, 12332);
                        }
                    }
                    Console.WriteLine("------------------------------------输出ID属性值--------------------------------------");
                    rTest = (ReflectionTest)object5;
                    Console.WriteLine(rTest.Id);
                    //2.获取类的字段
                    Console.WriteLine("------------------------------------2.获取类的字段--------------------------------------");
                    foreach (var item in type5.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
                    {
                        Console.WriteLine(item.Name);
                    }
    
                }

    六. 反射的好处和局限

     1  {
     2                //反射的好处:
     3                //反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。
     4                //有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。
     5 
     6                 //性能局限
     7                 Console.WriteLine("------------------------------测试普通方法和反射的耗时情况--------------------------------------");
     8                 {
     9                     //1.普通方法
    10                     Stopwatch watch = new Stopwatch();
    11                     watch.Start();
    12                     for (var i = 0; i < 1000000; i++)
    13                     {
    14                         DBHelper2 dh = new DBHelper2();
    15                         dh.Id = 1;
    16                         dh.Name = "maru";
    17                         dh.Query();
    18                     }
    19                     watch.Stop();
    20                     Console.WriteLine("普通方式花费{0}ms:",watch.ElapsedMilliseconds);
    21                 }
    22                 {
    23                     //2. 反射的方法
    24                     Stopwatch watch = new Stopwatch();
    25                     watch.Start();
    26                     Assembly assembley6 = Assembly.Load("DB.SQLServer");
    27                     Type type6 = assembley6.GetType("DB.SQLServer.DBHelper2");
    28                     for (var i = 0; i < 1000000; i++)
    29                     {
    30                         object obj6 = Activator.CreateInstance(type6);
    31                         foreach (var item in type6.GetProperties())
    32                         {
    33                             if (item.Name.Equals("Id"))
    34                             {
    35                                 item.SetValue(obj6, 1);
    36                             }
    37                             if (item.Name.Equals("Name"))
    38                             {
    39                                 item.SetValue(obj6, "maru");
    40                             }
    41                         }
    42                         MethodInfo m6 = type6.GetMethod("Query");
    43                         m6.Invoke(obj6, null);
    44                     }
    45                     watch.Stop();
    46                     Console.WriteLine("反射方式花费{0}ms:", watch.ElapsedMilliseconds);
    47                 }
    48             }

    运行结果:

     七. 补充:获取类的属性、方法、特性、构造函数等,设置属性值,获取属性值

    函数                                                                         说明
    GetConstructor(s)                  取得此类型的创建函数,其将回传一个ConstructorInfo对象或数组
    GetField(s)                             取得此类型中成员变量,其将回传一个FiledInfo对象或数组
    GetMember(s)                        取得此类中的成员,其类型可以是变量、事件、属性、方法及Nested Type,其将回传一个MemberInfo对象或数组
    GetEvent(s)                            取得此类型中的事件,其将回传一个EventInfo对象或数组
    GetProperty/GetProperties         取得此类型中的属性,其将回传一个PropertyInfo对象或数组
    GetNestedType(s)                  取得声明于此类型内类型,其将回传一个Type对象或数组
    GetCustomAttibutes                    取得绑定于此类型的Attitudes
    GetValue(t)                                  获取t对象的的属性值
    SetValue(t,"XXX")                        设置t对象的属性值为XXX

    实体代码:

     1  [Description("我是Person类")]
     2     public class Person
     3     {
     4         //1. 构造函数
     5         public Person()
     6         {
     7 
     8         }
     9         public Person(string sex)
    10         {
    11             this._Sex = sex;
    12         }
    13         //2. 属性
    14 
    15         [Description("我是id")]
    16         public string id { get; set; }
    17 
    18         [ReadOnly(true)]
    19         public string userName { get; set; }
    20 
    21         public string userPwd { get; set; }
    22 
    23         //3.成员变量
    24 
    25         public string _Sex = null;
    26 
    27         public int _Age;
    28 
    29         //4. 特性  [Description("我是id")]     [ReadOnly(true)]
    30 
    31         //5. 方法
    32         public string GetOwnSex()
    33         {
    34             return this._Sex;
    35         }
    36 
    37         //6. 事件
    38         public event Action MyEvent;
    39 
    40 
    41 
    42     }

    调用代码:

     1  Person person1 = new Person()
     2                 {
     3                     id = "123",
     4                     userName = "ypf",
     5                     userPwd = "123456",
     6                 };
     7                 //获取类
     8                 Type type = person1.GetType();
     9                 {
    10                     Console.WriteLine("---------------1. 获取构造函数-----------------");
    11                     ConstructorInfo[] constructorInfoList = type.GetConstructors();
    12                     for (int i = 0; i < constructorInfoList.Length; i++)
    13                     {
    14                         Console.WriteLine(constructorInfoList[i]);
    15                     }
    16                 }
    17                 {
    18                     Console.WriteLine("---------------2. 获取成员变量-----------------");
    19                     FieldInfo[] fielInforList = type.GetFields();
    20                     for (int i = 0; i < fielInforList.Length; i++)
    21                     {
    22                         Console.WriteLine(fielInforList[i]);
    23                     }
    24                 }
    25                 {
    26                     Console.WriteLine("---------------3. 获取成员-----------------");
    27                     MemberInfo[] memberInfoList = type.GetMembers();
    28                     for (int i = 0; i < memberInfoList.Length; i++)
    29                     {
    30                         Console.WriteLine(memberInfoList[i]);
    31                     }
    32                 }
    33                 {
    34                     Console.WriteLine("---------------4. 获取事件-----------------");
    35                     EventInfo[] eventInfoList = type.GetEvents();
    36                     for (int i = 0; i < eventInfoList.Length; i++)
    37                     {
    38                         Console.WriteLine(eventInfoList[i]);
    39                     }
    40                 }
    41                 {
    42                     Console.WriteLine("---------------5. 获取属性-----------------");
    43                     PropertyInfo[] propertyInfoList = type.GetProperties();
    44                     for (int i = 0; i < propertyInfoList.Length; i++)
    45                     {
    46                         Console.WriteLine(propertyInfoList[i]);
    47                     }
    48                 }
    49                 {
    50                     Console.WriteLine("---------------6. 获取特性-----------------");
    51                     //1. 获取属性上的特性
    52                     //因为这些测试所用的特性都是加在属性上的,所以要先获取属性
    53                     PropertyInfo[] propertyInfoList = type.GetProperties();
    54                     foreach (var item in propertyInfoList)
    55                     {
    56                         //获取该属性上的所有特性
    57                         object[] attributeInfoList = item.GetCustomAttributes(true);
    58                         foreach (var item2 in attributeInfoList)
    59                         {
    60                             Console.WriteLine("{0}属性上的特性为{1}", item, item2);
    61                         }
    62 
    63                     }
    64                     //2. 获取类上的属性
    65                     object[] attributeInfoList2 = type.GetCustomAttributes(true);
    66                     foreach (var item3 in attributeInfoList2)
    67                     {
    68                         Console.WriteLine("{0}类上的特性为{1}", type, item3);
    69                     }       
    70                 }
    71                 {
    72                     Console.WriteLine("---------------7. 获取id属性的值-----------------");
    73                     PropertyInfo idProperty = type.GetProperty("id");
    74                     Console.WriteLine("属性名为:{0}", idProperty.Name);
    75                     Console.WriteLine("属性值为:{0}", idProperty.GetValue(person1));
    76                     //设置属性值
    77                     idProperty.SetValue(person1, "2345");
    78                     Console.WriteLine("设置后的属性值为:{0}", idProperty.GetValue(person1));
    79 
    80                 }

    结果:

  • 相关阅读:
    U盘分区 将一个u盘分为3个区
    InnoDB索引最通俗的解释
    Centos7 安全加固
    final/static
    Java继承,方法重写
    UnrealEngine4血溅效果
    UnrealEngine4第一人称射击游戏之触碰掉血与掉盔甲功能实现
    UnrealEngine4第一人称射击游戏UI
    String字符串
    构造方法
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/6891286.html
Copyright © 2020-2023  润新知