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\学习 单个项目\反射\MyReflection\Ant.DB.SQLServer\bin\Debug\Ant.DB.SQLServer.dll");

            //加载方式三,dll文件的完全限定名(当期目录)
            //Assembly assembly=Assembly.LoadFrom("Ant.DB.SQLServer.dll");

            //加载方式四,跟上面是一样的,只是参数不一样(文件具体路径)
            Assembly assembly =Assembly.LoadFrom(@"E:\VS workspace\学习 单个项目\反射\MyReflection\Ant.DB.SQLServer\bin\Debug\Ant.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");//根据名称找到属性

  

结果:

 

7,反射调用方法的案例

【7.1】带返回值的

https://blog.csdn.net/ftell/article/details/81745908?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&utm_relevant_index=2

public class MyClass
{
    public string func1()
    {
        return "func1";
    }
    public string func2()
    {
        return "func2";
    }
    public string func3()
    {
        return "func3";
    }
    public string func4()
    {
        return "func4";
    }
    public void callFunc(string funcName)
    {
        MethodInfo method = GetType().GetMethod(funcName);
        Func<string> func = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), this, method);
        Console.Write(func() + " ");
    }
}

  

【7.2】带参数的,不带返回值的

        public void SetOut_0()
        {
            btnCh8_Click(null, null);
        }
        public void SetOut_1()
        {
            btnCh9_Click(null, null);
        }
        public void SetOut_2()
        {
            btnCh10_Click(null, null);
        }
        public void SetOut_3()
        {
            btnCh11_Click(null, null);
        }
        public void SetOut_4()
        {
            btnCh12_Click(null, null);
        }
        public void SetOut_5()
        {
            btnCh13_Click(null, null);
        }
        public void SetOut_6()
        {
            btnCh14_Click(null, null);
        }

        public void SetOut(string methodName)
        {
            MethodInfo method = GetType().GetMethod(methodName);
            method.Invoke(this, null);
        }

  

 

posted @ 2020-12-22 22:34  包子789654  阅读(280)  评论(0编辑  收藏  举报