反射(几种写法、好处和弊端、利用反射实现IOC)

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

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

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

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

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

 通过方法GetTypes来实现。

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

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

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

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

  通过方法GetConstructors来实现。

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

4. 获取类中的所有属性

  通过方法GetProperties来实现。

//1.加载程序集
Assembly assembly = Assembly.Load("DB.SQLServer");
//2.获取程序集中的特定类
Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
//3.获取特定类中的所有属性
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.加载程序集
Assembly assembly = Assembly.Load("DB.SQLServer");
//2.获取程序集中的特定类
Type tItem = assembly.GetType("DB.SQLServer.DBHelper");
//3.获取特定类中的所有接口
Type[] type = tItem.GetInterfaces();

二. 反射创建对象

1. 反射创建对象

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

1.1 ReflectionTest类的代码

public class ReflectionTest
{
    public int Id { get; set; }
    public string Name { get; set; }

    public string Field = null;
    public static string FieldStatic = null;


    #region 构造函数
    public ReflectionTest()
    {
        Console.WriteLine("这里是{0}无参数构造函数", this.GetType());
    }

    public ReflectionTest(string name)
    {
        Console.WriteLine("这里是{0} 有1个参数构造函数", this.GetType());
    }

    public ReflectionTest(int id, string name)
    {
        Console.WriteLine("这里是{0} 有2个参数构造函数", this.GetType());
    }
    #endregion

    public void Show1()
    {
        Console.WriteLine("这里是{0}的Show1", this.GetType());
    }

    public void Show2(int id)
    {

        Console.WriteLine("这里是{0}的Show2", this.GetType());
    }

    public static void ShowStatic(string name)
    {
        Console.WriteLine("这里是{0}的ShowStatic", typeof(ReflectionTest));
    }

    public void Show3()
    {
        Console.WriteLine("这里是{0}的Show3_1", this.GetType());
    }

    public void Show3(int id, string name)
    {
        Console.WriteLine("这里是{0}的Show3", this.GetType());
    }

    public void Show3(string name, int id)
    {
        Console.WriteLine("这里是{0}的Show3_2", this.GetType());
    }

    public void Show3(int id)
    {

        Console.WriteLine("这里是{0}的Show3_3", this.GetType());
    }

    public void Show3(string name)
    {

        Console.WriteLine("这里是{0}的Show3_4", this.GetType());
    }

    private void Show4(string name)
    {
        Console.WriteLine("这里是{0}的Show4", this.GetType());
    }
    public void ShowGeneric<T>(T name)
    {
        Console.WriteLine("这里是{0}的ShowStatic  T={1}", this.GetType(), typeof(T));
    }
}

1.2 反射创建对象的代码

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

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

   单例代码

public sealed class Singleton
{
    private Singleton()
    {
        Console.WriteLine("初始化一次");
    }

    private static Singleton Instance = new Singleton();

    public static Singleton CreateInstance()
    {
        return Instance;
    }
}

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

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

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

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

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

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

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

                                                     

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

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

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

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

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

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

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

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

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

配置文件:

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

简单工厂:

/// <summary>
/// 简单工厂,创建对象
/// </summary>
public class SimpleFactory
{
    private static string IDBHelperdllName = ConfigurationManager.AppSettings["IDBHelper-dllName"];
    private static string IDBHelperClassName = ConfigurationManager.AppSettings["IDBHelper-className"];

    public static IDBHelper CreateDBHelper()
    {
        Assembly assembly = Assembly.Load(IDBHelperdllName);
        Type type = assembly.GetType(IDBHelperClassName);
        object obj = Activator.CreateInstance(type);
        return (IDBHelper)obj;
    }

}

调用:

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

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

//2. 实例方法、静态方法、重载方法的调用
            {
                object obj = Activator.CreateInstance(tc5);
                Console.WriteLine("---------------------------------2.1 调用无参、有参的实例方法-------------------------------------");
                //2.1 调用无参、有参的实例方法
                {
                    MethodInfo methord = tc5.GetMethod("Show1");
                    methord.Invoke(obj, null);
                }
                {
                    MethodInfo methord = tc5.GetMethod("Show2");
                    methord.Invoke(obj, new object[]{11});
                }

                Console.WriteLine("---------------------------------2.2 调用静态方法-------------------------------------");
                //2.2 调用静态方法
                {
                    MethodInfo methord = tc5.GetMethod("ShowStatic");
                    methord.Invoke(obj, new object[] { "ShowStatic1234" });
                }

                Console.WriteLine("---------------------------------2.3 调用重载方法(需要在创建方法的时候,把类型传进去)-------------------------------------");
                //2.3 调用重载方法(需要在创建方法的时候,把类型传进去)
                {
                    MethodInfo methord = tc5.GetMethod("Show3", new Type[] { });
                    methord.Invoke(obj, null);
                }
                {
                    MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int)});
                    methord.Invoke(obj, new object[] { 11 });
                }
                {
                    MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string) });
                    methord.Invoke(obj, new object[] { "11" });
                }
                {
                    MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });
                    methord.Invoke(obj, new object[] { 11 ,"11"});
                }
                {
                    MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
                    methord.Invoke(obj, new object[] { "11",11 });
                }

                Console.WriteLine("---------------------------------2.4 调用私有方法-------------------------------------");
                //2.4 调用私有方法
                {
                    MethodInfo methord = tc5.GetMethod("Show4", BindingFlags.Instance|BindingFlags.NonPublic);
                    methord.Invoke(obj, new object[] { "11" });
                }
                Console.WriteLine("---------------------------------2.5 调用泛型方法-------------------------------------");
                //2.5 调用泛型方法
                {
                    MethodInfo methord = tc5.GetMethod("ShowGeneric");
                    methord = methord.MakeGenericMethod(typeof(string));
                    methord.Invoke(obj, new object[] { "123" });
                }

            }

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

{
                //实例化对象
                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);
                }

            }

六. 反射的好处和局限

{
               //反射的好处:
               //反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。
               //有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。

                //性能局限
                Console.WriteLine("------------------------------测试普通方法和反射的耗时情况--------------------------------------");
                {
                    //1.普通方法
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (var i = 0; i < 1000000; i++)
                    {
                        DBHelper2 dh = new DBHelper2();
                        dh.Id = 1;
                        dh.Name = "maru";
                        dh.Query();
                    }
                    watch.Stop();
                    Console.WriteLine("普通方式花费{0}ms:",watch.ElapsedMilliseconds);
                }
                {
                    //2. 反射的方法
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    Assembly assembley6 = Assembly.Load("DB.SQLServer");
                    Type type6 = assembley6.GetType("DB.SQLServer.DBHelper2");
                    for (var i = 0; i < 1000000; i++)
                    {
                        object obj6 = Activator.CreateInstance(type6);
                        foreach (var item in type6.GetProperties())
                        {
                            if (item.Name.Equals("Id"))
                            {
                                item.SetValue(obj6, 1);
                            }
                            if (item.Name.Equals("Name"))
                            {
                                item.SetValue(obj6, "maru");
                            }
                        }
                        MethodInfo m6 = type6.GetMethod("Query");
                        m6.Invoke(obj6, null);
                    }
                    watch.Stop();
                    Console.WriteLine("反射方式花费{0}ms:", watch.ElapsedMilliseconds);
                }
            }

运行结果:

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

函数                                                                         说明
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

实体代码:

[Description("我是Person类")]
    public class Person
    {
        //1. 构造函数
        public Person()
        {

        }
        public Person(string sex)
        {
            this._Sex = sex;
        }
        //2. 属性

        [Description("我是id")]
        public string id { get; set; }

        [ReadOnly(true)]
        public string userName { get; set; }

        public string userPwd { get; set; }

        //3.成员变量

        public string _Sex = null;

        public int _Age;

        //4. 特性  [Description("我是id")]     [ReadOnly(true)]

        //5. 方法
        public string GetOwnSex()
        {
            return this._Sex;
        }

        //6. 事件
        public event Action MyEvent;



    }

调用代码:

Person person1 = new Person()
                {
                    id = "123",
                    userName = "ypf",
                    userPwd = "123456",
                };
                //获取类
                Type type = person1.GetType();
                {
                    Console.WriteLine("---------------1. 获取构造函数-----------------");
                    ConstructorInfo[] constructorInfoList = type.GetConstructors();
                    for (int i = 0; i < constructorInfoList.Length; i++)
                    {
                        Console.WriteLine(constructorInfoList[i]);
                    }
                }
                {
                    Console.WriteLine("---------------2. 获取成员变量-----------------");
                    FieldInfo[] fielInforList = type.GetFields();
                    for (int i = 0; i < fielInforList.Length; i++)
                    {
                        Console.WriteLine(fielInforList[i]);
                    }
                }
                {
                    Console.WriteLine("---------------3. 获取成员-----------------");
                    MemberInfo[] memberInfoList = type.GetMembers();
                    for (int i = 0; i < memberInfoList.Length; i++)
                    {
                        Console.WriteLine(memberInfoList[i]);
                    }
                }
                {
                    Console.WriteLine("---------------4. 获取事件-----------------");
                    EventInfo[] eventInfoList = type.GetEvents();
                    for (int i = 0; i < eventInfoList.Length; i++)
                    {
                        Console.WriteLine(eventInfoList[i]);
                    }
                }
                {
                    Console.WriteLine("---------------5. 获取属性-----------------");
                    PropertyInfo[] propertyInfoList = type.GetProperties();
                    for (int i = 0; i < propertyInfoList.Length; i++)
                    {
                        Console.WriteLine(propertyInfoList[i]);
                    }
                }
                {
                    Console.WriteLine("---------------6. 获取特性-----------------");
                    //1. 获取属性上的特性
                    //因为这些测试所用的特性都是加在属性上的,所以要先获取属性
                    PropertyInfo[] propertyInfoList = type.GetProperties();
                    foreach (var item in propertyInfoList)
                    {
                        //获取该属性上的所有特性
                        object[] attributeInfoList = item.GetCustomAttributes(true);
                        foreach (var item2 in attributeInfoList)
                        {
                            Console.WriteLine("{0}属性上的特性为{1}", item, item2);
                        }

                    }
                    //2. 获取类上的属性
                    object[] attributeInfoList2 = type.GetCustomAttributes(true);
                    foreach (var item3 in attributeInfoList2)
                    {
                        Console.WriteLine("{0}类上的特性为{1}", type, item3);
                    }       
                }
                {
                    Console.WriteLine("---------------7. 获取id属性的值-----------------");
                    PropertyInfo idProperty = type.GetProperty("id");
                    Console.WriteLine("属性名为:{0}", idProperty.Name);
                    Console.WriteLine("属性值为:{0}", idProperty.GetValue(person1));
                    //设置属性值
                    idProperty.SetValue(person1, "2345");
                    Console.WriteLine("设置后的属性值为:{0}", idProperty.GetValue(person1));

                }

结果:

猜你喜欢

转载自blog.csdn.net/chengriyue/article/details/86491699