C#--反射基础

摘要:
以下是学习笔记:首先,反射DLL/EXE的基本信息:主要的区别是EXE文件有一个条目,DLL文件不能运行,但DLL可以被带到其他地方使用元数据:描述EXE/dl文件的列表,记录EXE/DLL文件中的类、属性、功能和字段…这也称为反射销毁单例模式。

以下是学习笔记:

一,反射的基本信息

C#--反射基础第1张

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+" 方法");
                }
            }

注意:

C#--反射基础第2张

三,通过反射创建对象

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不同类型的参数的构造函数

结果:

C#--反射基础第3张

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);

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

C#--反射基础第4张

五,通过反射调用方法

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" });//静态方法,对象可以为空
            }

结果:

C#--反射基础第5张

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");//根据名称找到属性

结果:

C#--反射基础第6张

免责声明:文章转载自《C#--反射基础》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WPS for linux 中不能切换到中文输入法BW:数据源抽取机制 . 沧海下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

将定时任务cron 解析成中文

    在使用定时器 quartz 时,其中的cron 表达式,老板表示作为开发的你能看懂外,其他的非开发同事可能看不懂,要用一个他们能看懂的方式表达出来。 还好我们的项目要求的表达式不是特别的麻烦,所以就写了一个简略的转换为中文的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22...

C#的post请求 捕获错误代码的内容

public string Query(stringqueryString) { try{ HttpWebRequest request =(HttpWebRequest)HttpWebRequest.Create(AOPResource.LVSRequestURL);...

odoo 项目经验1

1.在xml中的domain表达式解析:|,&,!以及表示此意义的符号,都是遵从栈的规则(后进先出),右为栈底,所以从最左端的符号开始判断。 2.xml中也可以进行时间计算,比如在一周内的为即将开始等等等。 可参照https://www.cnblogs.com/hellojesson/p/8144474.html <filter strin...

Android 异步加载解决方案

Android的Lazy Load主要体现在网络数据(图片)异步加载、数据库查询、复杂业务逻辑处理以及费时任务操作导致的异步处理等方面。在介绍Android开发过程中,异步处理这个常见的技术问题之前,我们简单回顾下Android开发过程中需要注意的几个地方。 Android应用开发过程中必须遵循单线程模型(Single Thread Model)的原则。因...

C++ ORM ODB入门

1.ORM ORM, Object Relational Mapping, 对象关系映射,用来将基于对象的数据结构映射到SQL的数据结构中。即将基于对象的数据映射到关系表中的字段,然后我们可以通过对象提供的接口来操作数据库,而无需写sql语句来操作数据库。一般一张关系表对应两个类,一个实体类和一个操作类。ORM是一种框架,而不是一种实现。 2.C++ 的O...

Web Service学习之六:CXF解决无法处理的数据类型

  CXF不能够处理像Map复杂的数据类型,需要单独转换处理。 总体思路:创建一个转换器和一个对应的可以处理的数据结构类型,将不能处理的类型转换成可以处理的类型: 步骤: 一、创建一个可以处理的类型 举例:要转换Map<String,User> package ws; import java.util.List; public class...