C#之反射

引用的:进击的NetER,地址:https://www.bilibili.com/video/BV19J411v7yk?from=search&seid=4031467641635957500

  c#编写的代码经过编译器编译,最终生成了dll(程序集,程序集采用的是公共中间语言CIL,或者简称为中间语言IL)或者exe文件,,此时的处理器是不认识这些文件的,为了将CIL代码转换成处理器能够理解的机器码,需要完成一个额外的步骤,通常在执行时进行。虚拟执行系统(VES),偶尔也称之为运行时,它根据需要来编译CIL代码,这个过程称之为即时编译或者JIT编译(just-in-time complelation)。假如代码在“运行时”这样一个“代理”的上下文中执行,就将这些代码称为托管代码,而在“运行时”的控制下的过程称为托管执行。之所以称为托管代码,是因为“运行时”管理着诸如内存分配,安全性和JIT编译等方面,从而控制了程序的主要行为。执行过程中不需要“运行时”的代码称为本机代码或非托管代码。

注意:dll或exe中包含了metada元数据和IL语言,元数据: 每个托管代码都包含元数据表,主要有两种表:一种表描述源代码中定义类和成员,另一种描述代码中引用的类型和成员。比如经常使用的泛型:

1.反射的定义

  反射是指对程序集中的元数据进行检查的过程。

2.获取某个程序集下面所有的类名称

              //动态加载dll:这是从exe所在路径查找,不需要加后缀
                Assembly assembly = Assembly.Load("Reflection.DB.Mysql");
                //这种是全路径:@加在字符串前面,字符串中的  失去转义符的作用,直接写字符串而不需要考虑转义字符,而且表示空格换行都保留着。
                Assembly assembly1 = Assembly.LoadFile(@"D:a_云数反射1ConsoleApp1ConsoleApp1inDebug
etcoreapp2.1Reflection.DB.Mysql.dll");
                //这也是在当前路径查找,这种和第一个相比仅仅是把后缀加上。
                Assembly assembly2 = Assembly.LoadFrom(@"D:a_云数反射1ConsoleApp1ConsoleApp1inDebug
etcoreapp2.1Reflection.DB.Mysql.dll");
                //获取 Type类型的当前对象的类型
                //获取当前dll中的所有类名称
                foreach (Type type in assembly1.GetTypes())
                {
                    //把Reflection.DB.Mysql.dll下面所有的类名称全部取出来了。
                    Console.WriteLine(type.Name);

                } 
                Console.ReadKey();

下面是这个类库下的所有类名称:

 

结果:

Class1
MySqlHelper

3.获取具体类中的方法

      #region  获取其中一个类中的方法并调用
                //使用反射之前的操作
              //  IDBHelper help = new SqlSrverHelper();
            //    help.Query();
                //1.动态加载
                Assembly assemblyOne = Assembly.Load("Reflection.DB.SqlServer");
                //2.获取Reflection.DB.SqlServer类库下的SqlSrverHelper类信息
                Type type1 = assemblyOne.GetType("Reflection.DB.SqlServer.SqlSrverHelper");
                //3.创建对象
                object objectStart = Activator.CreateInstance(type1);
                //4.类型转换
                IDBHelper helper = objectStart as IDBHelper;
                //调用方法
                helper.Query();


public class MySqlHelper: IDBHelper { /// <summary> /// 无参数的构造方法 /// </summary> public MySqlHelper() { Console.WriteLine("{0}被构造",this.GetType().Name); } public void Query() { Console.WriteLine("{0}.Query", this.GetType().Name); } }

结果:

注意:使用反射的时候还是先进入了无参的构造函数

SqlSrverHelper,被构造
SqlSrverHelper,Query

4. 

Object.ReferenceEquals(left, right)静态方法:从名称中便可知它用来比较两者是否是相同的引用,我们也永远不应该去重写该方法。它对于值类型对象的比较永远返回false;对于两个null的比较永远返回true。

                string peom1 = "Kubla Khan";
                string peom2 = "Kubla Khan"; 
                string peom3 = String.Copy(peom2);  
                //ReferenceEquals()判断两个字符串是否指向相同的内存地址  
                Console.WriteLine("peom1 == peom2:" + (peom1 == peom2));//True  
                Console.WriteLine("peom1 == peom3:" + (peom1 == peom3));//True  
                Console.WriteLine("ReferenceEquals(peom1,peom3):" + ReferenceEquals(peom1, peom3));//False  

                //Equals,先判断两个字符串有相同的内存位置,则两个字符串相等;否则逐字符比较两个字符串,判断是否相等  
                Console.WriteLine("Equal(peom1,peom3):" + String.Equals(peom1, peom2));//true  
                Console.WriteLine("Equal(peom1,peom3):" + String.Equals(peom1, peom3));//true 

结果:

peom1 == peom2:True
peom1 == peom3:True
ReferenceEquals(peom1,peom3):False
Equal(peom1,peom3):True
Equal(peom1,peom3):True

反射能够破坏单例模式(private,protected等访问修饰符在反射面前形同虚设) :

/// <summary>
    ///  单例模式: 能保证在进程中只有一个实例
    /// </summary>
    public sealed class Singleton
    {
        private static Singleton _Singleton =null;

        /// <summary>
        /// 私有 (1)
        /// </summary>
        private   Singleton()
        {
            Console.WriteLine("被构造");
        }
        /// <summary>
        /// 静态构造函数 (2)
        /// </summary>
        static Singleton()
        {
            _Singleton = new Singleton();
        }
         /// <summary>
        /// 静态构造函数 (3)
        /// </summary>
       public static Singleton GetInstance() { return _Singleton; } }

下面是不同的调用方法:

                Singleton s = Singleton.GetInstance();
                Singleton s1 = Singleton.GetInstance();
                Singleton s2 = Singleton.GetInstance();
                Console.WriteLine(object.ReferenceEquals(s,s2));

                
                //使用反射
                Assembly assembly = Assembly.Load("Reflection.DB.SqlServer");
                //获取类型
                Type type = assembly.GetType("Reflection.DB.SqlServer.Singleton");
                //创建对象
                object o1 = (Singleton)Activator.CreateInstance(type,true);
                object o2 = (Singleton)Activator.CreateInstance(type, true);
                object o3 = (Singleton)Activator.CreateInstance(type, true);
                Console.WriteLine(object.ReferenceEquals(o1, o3));//判断2者是否是同一个实例,

如上述代码,普通的实例化对象调用 Singleton 类中的GetInstance方法,在Singleton类中的步骤为2>1>3。这是第一次调用的步骤,之后就只会调用第3个步骤,因为_Singleton是一个静态变量,第一次赋值之后就可以直接获取了。

但是使用反射的话,可以直接访问私有的构造函数,直接且只执行(1).因为每次执行了一次构造函数,所以每次都是全新的实例,所以为False。

c#中的对未赋值的称为对象,赋值的之后称之为实例,实例化可以说是new 对象的过程。

 

结果:

被构造
True
被构造
被构造
被构造
False

 下面是使用反射调用类中的不同方法:

  //使用反射
                Assembly assembly = Assembly.Load("Reflection.DB.SqlServer");
                //获取类型
                Type type = assembly.GetType("Reflection.DB.SqlServer.ReflectionTest");
                //创建对象
                object oReflectionTest = Activator.CreateInstance(type);
                //获取特定方法
                MethodInfo method = type.GetMethod("Show2");//如果是所有方法的话则是 type.GetMethods()
                //调用方法: 
                method.Invoke(oReflectionTest, new object[] { 12});
                //调用重载方法,所以我们可以设置重载方法参数的类型顺序来接收,注意,前后顺序要一致。
                //这是调用重载方法之一的show3方法
                MethodInfo mesthodShow3 = type.GetMethod("Show3",new Type[] {typeof(int),typeof(string) });
                mesthodShow3.Invoke(oReflectionTest,new object[] {12,"重载方法" });
                //调用私有的方法Show4
                BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
                MethodInfo methodShow4 = type.GetMethod("Show4", flags);
                methodShow4.Invoke(oReflectionTest,new object[] { "私有方法"});
                //调用静态
                MethodInfo mesthodShow5 = type.GetMethod("Show5");
                mesthodShow5.Invoke(null,new object[] {"静态方法" });
ReflectionTest类:
    /// <summary>
    /// 反射测试类
    /// </summary>
    public class ReflectionTest
    {
        #region Identity
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public ReflectionTest()
        {
            Console.WriteLine("这是{0}的无参数构造函数",this.GetType());
        }
        /// <summary>
        /// 这是有参数的构造函数
        /// </summary>
        /// <param name="name"></param>
        public ReflectionTest(string name)
        {
            Console.WriteLine("这是{0}的构造函数", this.GetType());
        }
        public ReflectionTest(int id)
        {
            Console.WriteLine("这是{0}的构造函数", this.GetType());
        }
        public ReflectionTest(int id,string name)
        {
            Console.WriteLine("这是{0}的构造函数", this.GetType());
        }
        #endregion
        #region 方法

        public void Show1()
        { 
            Console.WriteLine("这是{0}的Show1", this.GetType());
        }
        
        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="id"></param>
        /// <param name="name"></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_5", 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 
    }
5.泛型与反射
测试的泛型类:
namespace Reflection.DB.SqlServer
{
    public class GenericClass<T, W, X>
    {
        public void Show(T t, W w, X x)
        {
            Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name+"-值:"+t, w.GetType().Name + "-值:" + w, x.GetType().Name + "-值:" + x);
        }
    }
    /// <summary>
    /// 普通类中含有泛型方法
    /// </summary>
    public class GenericMethod
    {
        public void Show<T, W, X>(T t, W w, X x)
        {
            Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name + "-值:" + t, w.GetType().Name + "-值:" + w, x.GetType().Name + "-值:" + x);
        }
    }

    public class GenericDouble<T>
    {
        public void Show<W, X>(T t, W w, X x)
        {
            Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name + "-值:" + t, w.GetType().Name + "-值:" + w, x.GetType().Name + "-值:" + x);
        }
    }

}
 
(1)调用普通类中的泛型
   //动态加载
                Assembly assembly = Assembly.Load("Reflection.DB.SqlServer");
                //获取类型
                Type type = assembly.GetType("Reflection.DB.SqlServer.GenericMethod");
                //创建对象
                object oReflection = Activator.CreateInstance(type);
                //获取泛型方法
                MethodInfo method = type.GetMethod("Show");
                //调用泛型的时候,反射同样需要指定确定的类型
                MethodInfo show = method.MakeGenericMethod(typeof(int),typeof(string), typeof(DateTime));
                //调用方法
                show.Invoke(oReflection,new object[] {12,"大地的时间:",DateTime.Now });

结果:

t.type=Int32-值:12,w.type=String-值:大地的时间:,x.type=DateTime-值:2020/5/2 17:34:13

 (2)调用泛型类中的泛型方法

                #region  泛型类中的泛型发方法与反射
                //动态加载
                Assembly assembly = Assembly.Load("Reflection.DB.SqlServer");
                //获取类型,GenericClass是三个参数泛型类
                Type type = assembly.GetType("Reflection.DB.SqlServer.GenericClass`3");
                //然后确定这个三个参数的具体类型
                Type genericType = type.MakeGenericType(new Type[] {typeof(int),typeof(string),typeof(DateTime)});
                //创建对象
                object oReflection = Activator.CreateInstance(genericType);
                //获取方法
                MethodInfo method = genericType.GetMethod("Show");
                //调用方法
                method.Invoke(oReflection,new object[] {2,"测试",DateTime.Now });
                #endregion
 结果:

t.type=Int32-值:2,w.type=String-值:测试,x.type=DateTime-值:2020/5/3 16:20:53


(3)调用泛型类和泛型方法参数不一致的情况
               //动态加载
                Assembly assembly = Assembly.Load("Reflection.DB.SqlServer");
                //获取类型,GenericClass是三个参数泛型类
                Type type = assembly.GetType("Reflection.DB.SqlServer.GenericDouble`1");
                //然后确定这个三个参数的具体类型
                Type genericType = type.MakeGenericType(new Type[] {typeof(int)});
                //创建对象
                object oReflection = Activator.CreateInstance(genericType);
                //获取方法
                MethodInfo method = genericType.GetMethod("Show");
                MethodInfo showMethod = method.MakeGenericMethod(new Type[] {typeof(string),typeof(DateTime) });
                //调用方法
                showMethod.Invoke(oReflection,new object[] {2,"测试",DateTime.Now });
 
结果:

t.type=Int32-值:2,w.type=String-值:测试,x.type=DateTime-值:2020/5/3 16:38:35








原文地址:https://www.cnblogs.com/anjingdian/p/12733163.html