20181112_反射基础_对象获取

一.   C#中的反射

什么是反射:在C#中, 反射是有System.Reflection命名空间下的, 由.Net框架提供帮助类库,可以读取并使用dll(或exe)文件的metadata(元数据)

二.   反射的基本写法, 介绍 Load / LoadFile / LoadFrom:

Assembly assembly = Assembly.Load("MyDB.MySql"); //通常推荐使用这一种
                    //第一步:  从 [当前目录] 加载指定名称的dll;dll名称无后缀 

                    //loadfile 从 指定目录 加载指定名称的dll; dll名称必须带上后缀
                    Assembly assembly_1 = Assembly.LoadFile(@"C:\CsharpProject\_Reflection\bin\Debug\MyDB.MySql.dll");
                    //LoadFile表示完整路径的加载, 所以可以是别的目录; 如果没有依赖项, 加载的时候也不会报错, 但是在使用的时候会错; 比如加载的是c:\windows\A.dll; 但是A内部依赖着B.dll; 此时如果没有同时加载B.dll, 那么在使用的时候就会报错

                    //Assembly assembly2 = Assembly.LoadFrom("Ruanmou.DB.MySql.dll");//使用LoadFrom加载的时候, 需要带后缀(dll/exe)或者 是文件的完整路径

                    //无论是LoadFile还是LoadFrom; 底层都是调用的Load()
                    //但是还是有区别, LoadFile不会在加载的时候, 去调用程序集的构造函数; 但是Load会的; 

foreach (var item in assembly.GetModules())
                    {
                        //输出模块信息; 这个GetModules里面就只有程序集的名称, 这里面有用的东西也就这个了
                        Console.WriteLine(item.FullyQualifiedName);
                    }

                    //assembly.GetTypes() 输出本程序集中, 所有类的类名信息; 包含命名空间的名称
                    foreach (var item in assembly.GetTypes())
                    {
                        //输出类型信息
                        Console.WriteLine(item.FullName);
                    }

                    //assembly.GetType→获取指定的某个类的信息; 参数为类的完整名称新包含程序集的名称;
                    //assembly.GetTypes();  获取所有类的信息; 返回一个type数组
                    Type type = assembly.GetType("MyDB.MySql.MySqlHelper");//第二步: 获取指定类型的信息
                    object oDBHelper = Activator.CreateInstance(type);//第三步: 通过反射创建对象
                   //oDBHelper.Query(); oDBHelper是objec不能调用, 而实际上方法是有的, 但是编译器不认可; 所以必须要类型转换
                    IDbHelper IDbHelper = (IDbHelper)oDBHelper;//第四步: 类型转换
                    IDbHelper.Query();//第五步: 方法调用

三. 反射的简单应用, 使用工厂+配置文件+反射 动态创建不同对象实例

a)         配置文件内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <!--MyDB.MySql.MySqlHelper   → 类名称-->
<!--MyDB.MySql  → dll名称-->
    <add key="IDbHelperConfig" value="MyDB.MySql.MySqlHelper,MyDB.MySql"/>

  </appSettings>
  <connectionStrings>
    <!--数据库连接字符串-->
    <add name="Customers" connectionString="Data Source=.; Database=OA; User ID=sa; Password=123456; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

b)         工厂类代码:

public class Factory
    {
        //使用工厂来创建对象, 完成对象创建的封装 ; 由于工厂中使用配置文件, 那么只需要再配置文件中换下配置字符串, 则就能使用不同的类, 代码一行都不需要改动; 同时还可以添加一个原本不存在的DLL, 但是要把需要的DLL复制到当前目录下
        /*
          <appSettings>
            <!--MyDB.MySql.MySqlHelper   → 类名称-->
            <!--MyDB.MySql  → dll名称-->
            <add key="IDbHelperConfig" value="MyDB.MySql.MySqlHelper,MyDB.MySql"/>
            </appSettings>
         */
        /// <summary>
        /// 从配置文件中, 获取程序集的路径
        /// </summary>
        private static string IDBHelperConfig = System.Configuration.ConfigurationManager.AppSettings["IDbHelperConfig"];
        /// <summary>
        /// dll的名称, 不包含后缀;
        /// </summary>
        private static string DllName = IDBHelperConfig.Split(‘,‘)[1];
        /// <summary>
        /// 类的名称; 用来从之前程序集中取出类名; 类名必须包含命名空间
        /// </summary>
        private static string TypeName = IDBHelperConfig.Split(‘,‘)[0];

        public static IDbHelper CreateHelper()//1 2
        {
            Assembly assembly = Assembly.Load(DllName);//1 加载dll
            Type type = assembly.GetType(TypeName);//2 获取类型信息
            object oDBHelper = Activator.CreateInstance(type);//3 创建对象
            IDbHelper iDBHelper = (IDbHelper)oDBHelper;//4 类型转换
            return iDBHelper;
        }
}

c)         调用:

IDbHelper iDbHeler = Factory.CreateHelper();// 使用工厂创建对象
iDbHeler.Query();//能够做到可配置可扩展的原因是: 反射是动态的, 它依赖的是字符串, 而字符串可以任何更改

d)         测试:

看下下面的两个图, 然后做修改:

将右图的value值修改为

MyDB.SqlServer.SqlServerHelper,MyDB.SqlServer

再次运行程序, 发现就是调用的SqlServer来处理数据层

四.   使用反射调用单例类的构造函数, 以其来破坏单例:

a)         单例类的代码如下:

public sealed class Singleton
    {
        private static Singleton _Singleton = null;
        private Singleton()
        {
            Console.WriteLine("Singleton被构造");
        }

        static Singleton()
        {
            _Singleton = new Singleton();
        }

        public static Singleton GetInstance()
        {
            return _Singleton;
        }
    }

b) 直接使用单例类, 程序中只能被实例化一次:

  //单例模式, 保证程序启动起来后, 这个类只能有一个实例; 下面代码只是测试
                    Singleton singleton1 = Singleton.GetInstance();
                    Singleton singleton2 = Singleton.GetInstance();
                    Singleton singleton3 = Singleton.GetInstance(); 

c)  使用反射调用单例的构造函数, 以其来创建多个不同实例

//反射破坏单例,主要就是调用单例的构造函数; 注意: 不管是反射还是什么技术, 只要能够多次调用它的构造函数, 就肯定能破坏单例
Assembly assembly = Assembly.Load("MyDB.SqlServer");
                  Type type = assembly.GetType("MyDB.SqlServer.Singleton");
                        //使用Singleton强制类型转换
                        //使用反射可以调用单例模式下类的私有构造函数; 如果想调用单例下的类进行反射则必须传递第二个参数为true ;
                        Singleton singleton4 = (Singleton)Activator.CreateInstance(type ,true);
                        Singleton singleton5 = (Singleton)Activator.CreateInstance(type,true );
                        Singleton singleton6 = (Singleton)Activator.CreateInstance(type, true);

 

五.   使用反射调用类的指定构造函数

a)         调用代码:

//调用有参数的构造函数进行反射; 使用new object[]{}
                        Assembly assembly = Assembly.Load("MyDB.SqlServer");
                        //加载测试类的dll文件
                        Type type = assembly.GetType("MyDB.SqlServer.ReflectionTest");
                        //默认调用无参构造函数
                        object oReflectionTest1 = Activator.CreateInstance(type);
                        //传递参数到构造函数, 构造函数类型/个数, 必须匹配
                        object oReflectionTest2 = Activator.CreateInstance(type, new object[] {123});
                        object oReflectionTest3 = Activator.CreateInstance(type, new object[] {"123"});

b)  ReflectionTest类的代码如下:

/// <summary>
    /// 反射测试类; 用来演示如何使用反射调用带参数的构造函数
    /// </summary>
    public class ReflectionTest
    {
        #region Identity
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public ReflectionTest()
        {
            Console.WriteLine("这里是{0}无参数构造函数", this.GetType());
        }

        /// <summary>
        /// 带参数构造函数string类型
        /// </summary>
        /// <param name="name"></param>
        public ReflectionTest(string name)
        {
            Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
        }
        /// <summary>
        /// 带参数构造函数的int类型重载
        /// </summary>
        /// <param name="id"></param>
        public ReflectionTest(int id)
        {
            Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
        }
        #endregion

        #region Method
        /// <summary>
        /// 无参方法
        /// </summary>
        public void Show1()
        {
            Console.WriteLine("这里是{0}的Show1", this.GetType());
        }
        /// <summary>
        /// 有参数方法
        /// </summary>
        /// <param name="id"></param>
        public void Show2(int id)
        {

            Console.WriteLine("这里是{0}的Show2", this.GetType());
        }
        /// <summary>
        /// 重载方法之一
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        public void Show3(int id, string name)
        {
            Console.WriteLine("这里是{0}的Show3", this.GetType());
        }
        /// <summary>
        /// 重载方法之二
        /// </summary>
        /// <param name="name"></param>
        /// <param name="id"></param>
        public void Show3(string name, int id)
        {
            Console.WriteLine("这里是{0}的Show3_2", this.GetType());
        }
        /// <summary>
        /// 重载方法之三
        /// </summary>
        /// <param name="id"></param>
        public void Show3(int id)
        {

            Console.WriteLine("这里是{0}的Show3_3", this.GetType());
        }
        /// <summary>
        /// 重载方法之四
        /// </summary>
        /// <param name="name"></param>
        public void Show3(string name)
        {

            Console.WriteLine("这里是{0}的Show3_4", this.GetType());
        }
        /// <summary>
        /// 重载方法之五
        /// </summary>
        public void Show3()
        {

            Console.WriteLine("这里是{0}的Show3_1", this.GetType());
        }
        /// <summary>
        /// 私有方法
        /// </summary>
        /// <param name="name"></param>
        private void Show4(string name)
        {
            Console.WriteLine("这里是{0}的Show4", this.GetType());
        }
        /// <summary>
        /// 静态方法
        /// </summary>
        /// <param name="name"></param>
        public static void Show5(string name)
        {
            Console.WriteLine("这里是{0}的Show5", typeof(ReflectionTest));
        }
        #endregion
    }

六.  使用反射获取类中的各个方法; 重载/静态/私有/泛型/父类

 Assembly assembly1 = Assembly.Load("MyDB.SqlServer");
                Type type1 = assembly1.GetType("MyDB.SqlServer.ReflectionTest");
                //type1.BaseType //表示获取他的父类型
                object oReflectionTest = Activator.CreateInstance(type1);

                //使用GetMethods获取该类下的所有方法
                foreach (var item in type1.GetMethods())
                {
                    //获取该类下所有的方法名称
                    Console.WriteLine(item.Name);
                }
                //oReflectionTest.Show1();
                {
                    //通过反射, 使用方法名称类获取方法;
                    MethodInfo method = type1.GetMethod("Show1");
                    //第一个参数是实例, 第二个参数是  参数列表
                    method.Invoke(oReflectionTest, null); //null 表示此方法无参数
                }
                {
                    //传递方法的名称
                    MethodInfo method = type1.GetMethod("Show2");
                    method.Invoke(oReflectionTest, new object[] { 123 });
                }
                {
                    //静态方法的调用 静态方法的两种调用方式都可以; 可以给实例, 也可以不给实例
                    MethodInfo method = type1.GetMethod("Show5");
                    method.Invoke(oReflectionTest, new object[] { "孙悟空" });
                    //注意调用静态方法是不需要实例化的, 只需要把参数传递过去就行了; 但是普通方法就不行
                    method.Invoke(null, new object[] { "八戒" });
                }
                {
                    //注意如果调用有多个重载的方法, 那么通过方法名调用的时候, 必定会报错, 因为它能找到多个, 所以必须要连同参数列表一起传递
                    MethodInfo method = type1.GetMethod("Show3", new Type[] { });
                    method.Invoke(oReflectionTest, new object[] { });
                }
                {
                    MethodInfo method = type1.GetMethod("Show3", new Type[] { typeof(int) });
                    //调用int类型的
                    method.Invoke(oReflectionTest, new object[] { 123 });
                }
                {
                    //调用string 类型的
                    MethodInfo method = type1.GetMethod("Show3", new Type[] { typeof(string) });
                    method.Invoke(oReflectionTest, new object[] { "Ant" });
                }
                {
                    MethodInfo method = type1.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });
                    method.Invoke(oReflectionTest, new object[] { 234, "W" });
                }
                {
                    MethodInfo method = type1.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
                    method.Invoke(oReflectionTest, new object[] { "W", 234 });
                }
                {
                    //如何调用私有方法
                    //注意Show4是私有方法 使用反射调用私有方法
                    MethodInfo method = type1.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);
                    method.Invoke(oReflectionTest, new object[] { "孙悟空" });
                }

  

 

 

原文地址:https://www.cnblogs.com/wxylog/p/9944733.html

时间: 2024-10-31 05:45:15

20181112_反射基础_对象获取的相关文章

java进阶之反射:反射基础之如何获取一个类以及如何获取这个类的所有属性和方法(1)

java学习一段时间之后,大家可能经常会听到反射这个词,那么说明java已经学习到一个高一点的层次了.接下来我会一步步和大家一起揭开java高级特性反射的神秘面纱. 首先介绍下类对象这个概念,可能会经常用到这个概念: 类对象:java中有句很经典的话"万事万物皆对象",相信大家都不陌生,这句话告诉了我们java的特征之一,那就是面向对象.java中类的概念我们都很熟悉,既然万事万物皆是对象,那么类是谁的对象呢?<对象的概念:一个类的实例>换句话说,类是谁的实例.如此就有了类

java基础_对象初始化过程

1.因为new Studen()用到了Student类,所以会把它从硬盘上加载进入内存 2.如果有static静态代码块就会随着类的加载而执行,还有静态成员方法和普通方法也会随着类的加载而被加载 3.在堆中开辟空间,分配内存地址 4.在堆中建立对象特有属性(非静态成员),并同时对特有属性进行默认初始化 5.对属性进行显示初始化 比如  在类中 String name="123"; 6.执行构造代码块,对所有对象进行初始化 7.执行对应的构造函数,对对象进行初始化(调用不同的构造函数)

java基础_对象转型

package java_test; /* 对象的转型: 1.对象的向上转型 子类转成父类 默认进行 父类引用指向子类对象 2.对象的向下转型 父类转成子类 强制进行 关键字: instanceof 测试左边的对象事都是右边类的实例 如果是返回true 不是返回false */ class Animals{ void sleep(){ System.out.println("睡觉中"); } } class Cas extends Animals{ void catchMouse(){

【java】java反射机制,动态获取对象的属性和对应的参数值,并属性按照字典序排序,Field.setAccessible()方法的说明【可用于微信支付 签名生成】

方法1:通过get()方法获取属性值 package com.sxd.test.controller; public class FirstCa{ private Integer num; private String name; private Boolean flag; public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; } public String getNam

反射基础

反射基础 反射用于在程序运行过程中,获取类里面的信息或发现程序集并运行的一个过程.通过反射可以获得.dll和.exe后缀的程序集里面的信息.使用反射可以看到一个程序集内部的类,接口,字段,属性,方法,特性等信息. 一.各种GetType().typeof的区别 首先就是获取Tyoe对象的来源不同: class Program { static void Main(string[] args) { Type t1 = Type.GetType("ConsoleApplication2.Person

C#反射基础知识和实战应用

首先来说一下什么是反射? 反射提供了封装程序集.模块和类型的对象(Type类型) 可以使用反射动态的创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后,可以调用类型的方法或访问其字段和属性 . 总之,有了反射,以前很多实现不了的功能都可以实现. 下面先来写一个小例子,体验一下反射是怎么一回事: 打开VS2010,新建一个控制台应用程序,在program.cs里面写代码 首先引入命名空间: using System.Reflection; 下如下代码: PropertyInfo l

黑马程序员-java基础-反射基础

------- android培训.java培训.期待与您交流! ---------- java的反射机制是java的特性之一,反射机制是构建框架技术的基础所在,使用反射可以使程序更加灵活,避免将程序写死在代码里.相对于很多初学者只接触过java基础的人,反射还是一个很朦胧难懂的概念,下面我们就来说一下反射的一些应用. java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能.java反射有3个动态性质:1.运行时生成对象实例,2.运行期间调用发放,3.运行时更改属性. 那么反射

java反射基础知识(一)

一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 要想解剖一个类,必须先要获取到该类的字节码文件对象.而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.对于反射的操作实际上就是通过Class对象获取: *a.java.lang.reflect.Field:提供有关类或接口的单个

java反射基础知识(四)反射应用实践

反射基础 p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start. 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class,在Java中我们有三种方法可以获取一个对象的反射类. 通过getClass方法 在Java中,每一个Object都有一个getClass()方法,通过getClass方法我们可以获取到这个对象对应的反射类: 1 2 String s = "ziwenxie"; Class