• C#--反射基础


    以下是学习笔记:

    一,反射的基本信息

    DLL/EXE: 主要区别EXE文件有一个入口,DLL文件不能运行,但是DLL能拿到其他地方去使用

    metadata(元数据):描述exe/dll文件的一个清单,记录了exe/dll文件中有哪些类,属性,特性,字段。。。

    Reflection(反射):用来操作或获取元数据metadata

    有什么作用:

    1,更新程序(更新自己的DLL)

    一个工程有多个项目,更新其中一个小项目,就是替换一个dll文件就可以了

    2,使用别人的DLL文件(这种可以读取别人的私有的东西)

    反射是什么:就是一个操作metadata的一个类库(可以把反射当成一个小工具,用来读取或操作元数据的)

    使用场景:asp.net MVC ,ORM,LOC,AOP,几乎所有的框架都会使用反射

    二,通过反射加载DLL文件

    代码:

                //加载方式一,dll文件名(当前目录)
                //Assembly assembly=Assembly.Load("Ant.DB.SQLServer");
    
                //加载方式二,dll文件的完整路径(文件具体路径)
                //Assembly assembly=Assembly.LoadFile(@"E:VS workspace学习 单个项目反射MyReflectionAnt.DB.SQLServerinDebugAnt.DB.SQLServer.dll");
    
                //加载方式三,dll文件的完全限定名(当期目录)
                //Assembly assembly=Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //加载方式四,跟上面是一样的,只是参数不一样(文件具体路径)
                Assembly assembly =Assembly.LoadFrom(@"E:VS workspace学习 单个项目反射MyReflectionAnt.DB.SQLServerinDebugAnt.DB.SQLServer.dll");
    
                //注意:方式一的文件是当前目录的,因为在引用里面添加了项目的。
                //    如果第三方的需要复制到项目里面,或者用文件具体路径
    
                foreach (var type in assembly.GetTypes())//找所有类型
                {
                    Console.WriteLine(type.Name);
    
                    foreach (var method in type.GetMethods())//找所有方法
                    {
                        Console.WriteLine("这是:"+method.Name+" 方法");
                    }
                }
    

      注意:

    三,通过反射创建对象

    1,使用反射创建对象(无参数的构造函数)

     //【1】加载DLL文件
                Assembly assembly2 =Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                //Type type2 = assembly2.GetType("MySQLServerHelper");//只写一个类名是不行的
                Type type2 = assembly2.GetType("Ant.DB.SQLServer.MySQLServerHelper");//需要 命名空间.类名
    
                //【3】创建对象
                object oDbHelper = Activator.CreateInstance(type2);
                //上面等同于 MySQLServerHelper mySqlServerHelper=new MySQLServerHelper();
                IDBHelper dBHelper=oDbHelper as IDBHelper;//类型转换(as转换不报错,类型不对就返回null)
                //IDBHelper dBHelper2 =(IDBHelper)oDbHelper;//不用as转换,类型不对就报错
    
                //【4】调用对象的方法
                dBHelper.Query();
    

      

    2,使用反射创建对象(带参数的构造函数)

     //【1】加载DLL文件
                Assembly assembly3 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type3 = assembly3.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称
    
                //获取到这个类型下面的所有构造方法
                foreach (ConstructorInfo ctor in type3.GetConstructors())//获取所有的构造方法
                {
                    Console.WriteLine(ctor.Name);
                    foreach (var parameter in ctor.GetParameters())//获取构造方法的所有参数类型
                    {
                        Console.WriteLine(parameter.ParameterType);//显示类型名称
                    }
                }
    
                //【3】创建对象
                object oDbHelper3_1 = Activator.CreateInstance(type3);//无参数的构造函数
                object oDbHelper3_2 = Activator.CreateInstance(type3,new object[]{"Ant 编程"});//有1个参数的构造函数
                object oDbHelper3_3 = Activator.CreateInstance(type3,new object[]{123});//有1个参数的构造函数
                object oDbHelper3_4 = Activator.CreateInstance(type3,new object[]{123,"Ant 编程"});//有2不同类型的参数的构造函数
    

      

    结果:

    3,使用反射创建对象(私有的构造函数)

                Console.WriteLine("---------------------------UseReflection 使用反射创建对象(私有的构造函数)-------------------------");
                //PrivateCtor privateCtor=new PrivateCtor();//私有构造函数,这样创建直接报错的
    
                //【1】加载DLL文件
                Assembly assembly4 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type4 = assembly4.GetType("Ant.DB.SQLServer.PrivateCtor");//需要 命名空间.类型名称
    
                //【3】创建对象
                object oPrivate = Activator.CreateInstance(type4, true);//需要参数2,true,就可以创建私有构造函数的对象啦
    
                //这个功能 还用在我们的单例模式里面(一个对象只能创建一次) 。这个也叫反射破坏单例模式。
    

      

    四,通过反射创建创建泛型类

    1,使用反射创建泛型类

    泛型类:

    namespace Ant.DB.SQLServer
    {
        /// <summary>
        /// 泛型类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="W"></typeparam>
        /// <typeparam name="S"></typeparam>
        public class GenericClass<T,W,S>
        {
        }
    }
    

      

                Console.WriteLine("---------------------------UseReflection 使用反射创建泛型类-------------------------");
    
                //【1】加载DLL文件
                Assembly assembly5 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                //Type type5 = assembly5.GetType("Ant.DB.SQLServer.GenericClass");//需要 命名空间.类型名称
                Type type5 = assembly5.GetType("Ant.DB.SQLServer.GenericClass`3");//反单引号+参数的个数(3就是3个泛型类型的参数个数)
    
                //把参数类型给上面的type5
                Type makType= type5.MakeGenericType(new Type[] {typeof(int), typeof(string), typeof(double)});//typeof(int)获取到类型的具体类型
    
    
                //【3】创建泛型类的对象
                object oGeneric = Activator.CreateInstance(makType);
    

      

    使用反射创建泛型类的注意事项:

    五,通过反射调用方法

    1,类的方法代码:

    namespace Ant.DB.SQLServer
    {
        class ReflectionTest
        {
            public ReflectionTest()
            {
                Console.WriteLine($"这是{this.GetType()}无参数的构造函数");
            }
    
            public ReflectionTest(string name)
            {
                Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{name.GetType()}");
            }
    
            public ReflectionTest(int id)
            {
                Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{id.GetType()}");
            }
    
            public ReflectionTest(int id,string name)
            {
                Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{id.GetType()}和{name.GetType()}");
            }
    
            public void Test1()
            {
                Console.WriteLine($"这里是{this.GetType()}的Test1");
            }
    
            public void Test2(int id)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test2");
            }
    
            public void Test3(int id,string name)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test3-1");
            }
    
            public void Test3(string name, int  id)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test3-2");
            }
    
            public void Test3( int id)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test3-3");
            }
    
            public void Test3(string name)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test3-4");
            }
    
            public void Test3()
            {
                Console.WriteLine($"这里是{this.GetType()}的Test3-5");
            }
    
            //私有方法
            private void Test4(string name)
            {
                Console.WriteLine($"这里是{this.GetType()}的Test4的私有方法");
            }
    
            //静态方法
            public static void Test5(string name)
            {
                Console.WriteLine($"这里是{typeof(ReflectionTest)}的Test5的静态方法");
            }
        }
    }
    

      

    2,使用反射调用方法:

                Console.WriteLine("---------------------------UseReflection 使用反射调用方法-------------------------");
    
                //【1】加载DLL文件
                Assembly assembly6 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type6 = assembly6.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称
    
                //【3】创建对象
                object oReflection = Activator.CreateInstance(type6);//无参数的构造函数
    
                //获取类型的所有方法和参数
                foreach (var method in type6.GetMethods())
                {
                    Console.WriteLine("方法:"+method.Name);
                    foreach (var parameters in method.GetParameters())
                    {
                        Console.WriteLine("参数名:"+parameters.Name+",参数类型:"+parameters.ParameterType);
                    }
                }
    
                {
                    //【4】获取方法
                    //1,通过方法名来调用方法
                    MethodInfo methodInfo = type6.GetMethod("Test1");
    
                    //【5】调用无参数的方法
                    methodInfo.Invoke(oReflection, null);
                }
                {
                    MethodInfo methodInfo = type6.GetMethod("Test2");
                    //调用带参数的方法
                    methodInfo.Invoke(oReflection, new Object[]{123456});
                }
                {
                    //带参数的重载方法
                    MethodInfo methodInfo = type6.GetMethod("Test3",new Type[]{typeof(int),typeof(string)});//重载方法注意:指定参数类型
                    methodInfo.Invoke(oReflection, new Object[] { 123456,"jason" });//传入参数类型
                }
                {
                    MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(string), typeof(int) });
                    methodInfo.Invoke(oReflection, new Object[] { "jason" ,123456});
                }
                {
                    MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(int) });
                    methodInfo.Invoke(oReflection, new Object[] {  123456 });
                }
                {
                    MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(string) });
                    methodInfo.Invoke(oReflection, new Object[] { "jason"});
                }
                {
                    //无参数的重载方法
                    MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] {});
                    methodInfo.Invoke(oReflection, null);
                }
                {
                    //静态方法的调用方式1
                    MethodInfo methodInfo = type6.GetMethod("Test5");
                    methodInfo.Invoke(oReflection, new object[]{"jason"});
                }
                {
                    //静态方法的调用方式2
                    MethodInfo methodInfo = type6.GetMethod("Test5");
                    methodInfo.Invoke(null, new object[] { "jason" });//静态方法,对象可以为空
                }
    

      

    结果:

    3,通过反射调用私有方法

                Console.WriteLine("---------------------------UseReflection 使用反射调用私有方法-------------------------");
    
                //【1】加载DLL文件
                Assembly assembly7 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type7 = assembly7.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称
    
                //【3】创建对象
                object oReflection7 = Activator.CreateInstance(type7);//无参数的构造函数
    
                {
                    //【4】获取私有方法
                    //1,通过方法名来调用方法
                    //MethodInfo methodInfo = type6.GetMethod("Test4");//私有方法,直接给一个方法名还是不行的
                    MethodInfo methodInfo = type6.GetMethod("Test4",BindingFlags.Instance|BindingFlags.NonPublic);//获取私有方法需要,参数2:备注,一个说明,指定是一个实例,说明是非公开的
    
                    //【5】调用带参数的私有方法
                    methodInfo.Invoke(oReflection7, new object[]{"json"});
                }
    

      

    4,使用反射调用泛型方法(普通类里面的泛型方法调用)

    泛型类和泛型方法的示例代码:

    namespace Ant.DB.SQLServer
    {
        /// <summary>
        /// 泛型类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="W"></typeparam>
        /// <typeparam name="S"></typeparam>
        public class GenericClass<T,W,S>
        {
            /// <summary>
            /// 泛型方法
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <typeparam name="W"></typeparam>
            /// <typeparam name="S"></typeparam>
            /// <param name="t"></param>
            /// <param name="w"></param>
            /// <param name="s"></param>
            public void Test<T,W,S>(T t, W w, S s)
            {
                Console.WriteLine($"第一个类型是={t.GetType().Name},第二个类型是={w.GetType().Name},第三个类型是={s.GetType().Name},");
            }
        }
    
        /// <summary>
        /// 普通的类
        /// </summary>
        public class GenericMethod
        {
            /// <summary>
            /// 泛型方法
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <typeparam name="W"></typeparam>
            /// <typeparam name="S"></typeparam>
            /// <param name="t"></param>
            /// <param name="w"></param>
            /// <param name="s"></param>
            public void Test<T,W,S>(T t, W w, S s)
            {
                Console.WriteLine($"第一个类型是={t.GetType().Name},第二个类型是={w.GetType().Name},第三个类型是={s.GetType().Name},");
            }
        }
    }
    

      

                Console.WriteLine("---------------------------UseReflection 使用反射调用泛型方法(普通类里面的泛型方法调用)-------------------------");
    
                //【1】加载DLL文件
                Assembly assembly8 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type8 = assembly8.GetType("Ant.DB.SQLServer.GenericMethod");//需要 命名空间.类型名称
    
                //【3】创建对象
                object oReflection8 = Activator.CreateInstance(type8);//实例化类型
    
                //【4】通过方法名找到方法
                MethodInfo methodInfo8 = type8.GetMethod("Test");
    
                //【5】确定方法的参数类型和个数
                var methodGeneric = methodInfo8.MakeGenericMethod(new Type[] { typeof(int),typeof(string),typeof(DateTime)});
    
                //【6】调用方法
                methodGeneric.Invoke(oReflection8, new object[] {123456, "jason", DateTime.Now});
    

      

    5,使用反射调用泛型方法(泛型类里面的泛型方法调用)

                Console.WriteLine("---------------------------UseReflection 使用反射调用泛型方法(泛型类里面的泛型方法调用)-------------------------");
    
                //【1】加载DLL文件
                Assembly assembly9 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                //Type type9 = assembly9.GetType("Ant.DB.SQLServer.GenericClass");//需要 命名空间.类型名称,这个普通的方法不能获取泛型类型的
                Type type9 = assembly9.GetType("Ant.DB.SQLServer.GenericClass`3");//注意:泛型类需要:  反单引号+参数个数
    
                //【3】确定泛型方法的参数类型
                Type typeNew9 = type9.MakeGenericType(new Type[] {typeof(int), typeof(string), typeof(DateTime)});
    
                //【4】创建对象
                //object oReflection9 = Activator.CreateInstance(type9);//实例化类型
                object oReflection9 = Activator.CreateInstance(typeNew9);//实例化类型,需要用新的这个typeNew9
    
                //【5】通过方法名找到方法
                MethodInfo methodInfo9 = typeNew9.GetMethod("Test");//需要用新的这个typeNew9
    
                //【6】确定方法的参数类型和个数
                var methodGeneric9 = methodInfo9.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
    
                //【7】调用方法
                methodGeneric9.Invoke(oReflection9, new object[] { 123456, "jason", DateTime.Now });
    

      

    六,使用反射操作字段和属性等成员

    要操作的Studnet类的成员

    namespace Ant.DB.SQLServer
    {
        public class Student
        {
            public int Id { get; set; }
            public string StudentName { get; set; }
            public string StudentAddress { get; set; }
    
            public int age;
    
            public void Test()
            {
    
            }
        }
    }
    

      

                Console.WriteLine("---------------------------UseReflection 使用反射操作字段和属性等成员-------------------------");
                Student student = new Student()
                {
                    Id = 1,
                    StudentAddress = "杭州",
                    StudentName = "jason"
                };
    
    
                //【1】加载DLL文件
                Assembly assembly10 = Assembly.LoadFrom("Ant.DB.SQLServer.dll");
    
                //【2】DLL文件中有很多类型,获取类型(要完整的类型名称)
                Type type10 = assembly10.GetType("Ant.DB.SQLServer.Student"); //需要 命名空间.类型名称,这个普通的方法不能获取泛型类型的
    
                //【3】创建对象
                object oReflection10 = Activator.CreateInstance(type10); //实例化类型
    
                //方式一:获取和设置属性
                foreach (var prop in type10.GetProperties())
                {
                    Console.WriteLine($"类型:{prop.PropertyType},属性名称:{prop.Name},值:{prop.GetValue(student)}");//注意,这个student是上面的new出来的那个
                    Console.WriteLine("---------------------------------------");
                    if (prop.Name.Equals("Id"))
                    {
                        prop.SetValue(student, 2);
                    }
    
                    if (prop.Name.Equals("StudentAddress"))
                    {
                        prop.SetValue(student, "杭州2");
                    }
    
                    if (prop.Name.Equals("StudentName"))
                    {
                        prop.SetValue(student, "jason2");
                    }
    
                    Console.WriteLine($"类型:{prop.PropertyType},属性名称:{prop.Name},值:{prop.GetValue(student)}");
                }
    
                //方式二:获取和设置属性
                MemberInfo[] memberInfos=type10.GetMembers();//所有的成员信息,包括属性,字段,方法
                PropertyInfo[] propertyInfos = type10.GetProperties();//查找所有的属性
                PropertyInfo propertyInfo = type10.GetProperty("Id");//根据名称找到属性
    

      

    结果:

  • 相关阅读:
    Android平板电脑开发实战详解和典型案例
    UG NX10.0技术大全(不附光盘)
    SolidWorks 2018中文版机械设计应用大全
    1192.回文字符串
    1193.矩阵转置
    1195.最长&最短文本
    1194.八进制
    1196.成绩排序
    1197.奇偶检验
    1199.找位置
  • 原文地址:https://www.cnblogs.com/baozi789654/p/14165860.html
Copyright © 2020-2023  润新知