zoukankan      html  css  js  c++  java
  • 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








  • 相关阅读:
    linux中使用pthread_kill函数测试线程是否存活的例子
    jQuery的位置函数(offset(),innerWidth(),innerHeight(),outerWidth(),outerHeight(),scrollTop(),scrollLeft())小应用
    解决this.disabled=true;不能执行服务器端代码的问题(点击后按钮变不可用状态)
    sql trim()函数去掉两头空格
    五一结婚,收集祝福。附我的结婚对联,结婚放大像。
    错误提示:操作必须使用一个可更新的查询。
    C#:按精度四舍五入
    Javascript四舍五入(Math.round()与Math.pow())
    javascript与jQuery设置取得div绝对位置一个小应用(像日历控件一样,在编辑框下面显示一个层)
    jQuery取得select选中的值
  • 原文地址:https://www.cnblogs.com/anjingdian/p/12733163.html
Copyright © 2011-2022 走看看