6.C#知识点:反射

1.反光是什么样?

  反射提供描述组件,模块和项目标靶子(类型为Type)。您可以运用反射来动态成立类型的实例,将品种绑定到现有对象,或从现有对象得到项目,并调用其方法或访问其字段和性质。假诺你在代码中使用质量,反射使您可以访问它们。有关越多音讯,请参阅属性。—–来自微软官方。

  微软的分解自身认为还能。用大白话讲就是我们可以以通过反射让我们领悟未知类型的消息。类似现实生活中的B超啊。医务人员用B超看到孕妇肚子里的里边情形,因为大夫不知所可从内部查看。反射也是均等,对于未知类型。只怕引用过来的dll。大家是不知情里面景色的。可是可以透过反射。蝙蝠的超声波也是。通过声波反射回来,得知前方是还是不是有阻力。那就是反光的成效。若是要问反射内部是如何贯彻的。不好意思。近年来本身也不通晓。哈哈哈哈。

  简单的来说,我们的程序是由dll的结合的,dll里面有巨大的类组成。类里面又有字段,属性和情势。反射的意义就是给个dll就能明白有何样类,通过类又能清楚有如何成员。那么.net里面的反射是如何做到呢?那下边就要介绍多少个品类的反射类了。

   
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及今后程序集中查找类型并创办该类型的实例。 
   
(2)使用Module通晓蕴涵模块的主次集以及模块中的类等,还足以拿走在模块上定义的拥有全局方法或其余特定的非全局方法。 
   
(3)使用ConstructorInfo领会构造函数的称谓、参数、访问修饰符(如pulic
或private)和落实详细消息(如abstract或virtual)等。 
   
(4)使用MethodInfo通晓方法的称谓、重返类型、参数、访问修饰符(如pulic
或private)和兑现详细消息(如abstract或virtual)等。
   
(5)使用FiedInfo明白字段的名称、访问修饰符(如public或private)和贯彻详细消息(如static)等,并拿走或安装字段值。
   
(6)使用伊芙ntInfo精晓事件的名目、事件处理程序数据类型、自定义属性、申明类型和反光类型等,添加或移除事件处理程序。 
   
(7)使用PropertyInfo明白属性的名目、数据类型、讲明类型、反射类型和只读或可写状态等,获取或安装属性值。 
   
(8)使用ParameterInfo了然参数的名目、数据类型、是输入参数照旧出口参数,以及参数在章程签名中的地点等。那段话是从大牛的博客拷贝——->传送门

  

下边作者逐一重点的牵线多少个详细的类。

率先是Assembly。这几个存在于System.Reflection命名空间下边。作者第2讲它的二个加载程序集的的办法和分歧。Load,LoadForm,LoadFile。

讲了那样多文字,先从代码看看语法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            //加载程序集
            Assembly assembly = Assembly.Load("TestDLL");

            //输出程序集的强名称
            Console.WriteLine(assembly.FullName);
            Console.ReadKey();
        }
    }
}

图片 1

Load方法就是经进度序集的的名称加载程序,然则急须要加载的程序集在脚下程序集的bin目录下才能找得到。

LoadForm

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region Load方法
                    //加载程序集
                   // Assembly assembly = Assembly.Load("TestDLL");

                    //输出程序集的强名称
                    //Console.WriteLine(assembly.FullName);
                    //Console.ReadKey();
            #endregion

            Assembly assmbly1 = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
            Console.WriteLine(assmbly1.FullName);
            Console.ReadKey();
        }
    }
}

LoadForm是透过路径进行创办。重临加载的顺序集。

来看最后三个loadFile

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region Load方法
            //加载程序集
            // Assembly assembly = Assembly.Load("TestDLL");

            //输出程序集的强名称
            //Console.WriteLine(assembly.FullName);
            //Console.ReadKey();
            #endregion

            #region LoadFrom方法
            //Assembly assmbly1 = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
            //Console.WriteLine(assmbly1.FullName);
            ///Console.ReadKey();
            #endregion

            #region LoadFile方法
            Assembly assmbly2 = Assembly.LoadFile(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
            Console.WriteLine(assmbly2.FullName);
            Console.ReadKey();
            #endregion
        }
    }
}

本条多个办立陶宛(Lithuania)语法都很粗略。将来以来说这几个多少个的分歧,和优缺点。

LoadFrom和Load:LoadForm同3个先后集只加载一次,即便加载了不通的不二法门相同的程序集,他也只可以给您回到以前的程序集,LoadFrom只好用于加载不同标识的程序集,
约等于绝无仅有的程序集, 不大概用于加载标识相同但路径区其余顺序集。 

LoadFile和LoadForm:loadFile只会加载自己程序集,不会加在其引用的程序集,LoadForm和Load是会加载的其引述程序集。而且LoadFile同1个顺序集只可以加载四遍。那一个和LoadForm是同等。

从品质上看
LoadForm没有Load好,作用上也是load强一点。应用的时候如若loadFom和load都满足须要,指出用load。

那多少个方法还多少个重载版本。由于本片只是基础篇。篇幅不宜过多。想深刻摸底的伴儿可以查询MSN看看文档。最详尽的辨证就是文档。不过文档说的比较合法。结合大牛们写的博客。更易于懂一些。

好了大家开端下2个品级了。程序集将来我们得了。我起来看看程序集里面有些什么?

图片 2

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {


            #region LoadFrom方法
            Assembly assmbly = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
            Type[] types = assmbly.GetTypes();
            foreach (var item in types)
            {
                Console.WriteLine("类:"+item.Name);

            }
            Console.ReadKey();
            #endregion

        }
    }
}

图片 3

assmbly.GetTypes()这个方法或获取了所有类。
下面我我展示下获取字段和方法的字段

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {


            #region LoadFrom方法
            Assembly assmbly = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
            Type[] types = assmbly.GetTypes();
            foreach (var classitem in types)
            {
                Console.WriteLine("类:"+ classitem.Name);
                foreach (var fileditem in classitem.GetFields())
                {
                    Console.WriteLine("字段名:"+ fileditem.Name);
                }
                foreach (var methodItem in classitem.GetMethods())
                {
                    Console.WriteLine("方法名:"+methodItem.Name);
                }

            }
            Console.ReadKey();
            #endregion

        }
    }
}

 

可以看的出来大家将字段和方法名都给反射出来了,不过有个难题就是大家父类的主意也给弄出来了。我们得以修改下。那些地方有个重载版本。GetMethods有个重载方法可以经过BindingFlags枚举参数举办筛选父类的措施,或许其他的。 BindingFlags这些枚举类型。那里就不多讲。将来作者会逐渐补全。

简简单单的就是这么多了。反射能做过多业务,卓殊灵活。大家抽象工厂里面就会用到反射。大家的厂子。就是经过反射创制出来。下边作者写个demo演示下其听从。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assmbly = Assembly.Load("TestDLL");
            SqlServerHelper helper =(SqlServerHelper)assmbly.CreateInstance("TestDLL.SqlServerHelper");
            helper.Query();
            Console.ReadKey();
        }
    }
}

同伴们得以窥见。大家实例化了2个SqlServerHelper对象,不过大家向来不用健康的new方法,而是用了反光。这么些时候有些小伙伴或者就会说那是脱裤子放屁,间接new多不难。在此处是不利,不过放在确实的门类里一向new是当时爽,需要变动就等着哭啊,比如说未来领导对您说,集团的数据库不用SqlServer了,换到Oracle了。那是时候即使您是new的话还要改那里的代码,实际情况或许更复杂。不过用了我们的反光,那种不快就不会存在了。

CreateInstance(“TestDLL.SqlServerHelper”)
这一个形式参数大家一齐能够通过布置文件修改。那个类就不须要变了。作者来演示下代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestDLL
{
    public interface IDBHelper
    {
        void Query();
    }
}

 先创设五个预定数据操作的接口
IDBHlper类。规定有一个Query方法,然后让SqlServerHelper继承这几个接口,并且完毕那几个方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestDLL
{
    public class SqlServerHelper: IDBHelper
    {
        public void Query()
        {
            Console.WriteLine("这是测试");
        }
    }
}

 然后修改mian函数的办法

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="Helper" value="TestDLL.SqlServerHelper"/>
  </appSettings>
</configuration>

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assmbly = Assembly.Load("TestDLL");
            string helperkey = ConfigurationManager.AppSettings["Helper"];
            IDBHelper helper =(IDBHelper)assmbly.CreateInstance(helperkey);
            helper.Query();
            Console.ReadKey();
        }
    }
}

这会儿借使要将mian函数里面helper切换到Oracle的若是加上叁个两次三番于IDBheper接口的类,然后完成情势,在修改配置文件指向这么些类,然后就足以了。对于main函数大家是一些不须求动的,那是就是大家有着的高内聚低耦合。落成解耦。易于修改。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestDLL
{
    public class OracleHelper : IDBHelper
    {
        public void Query()
        {
            Console.WriteLine("我是Orcle数据库");
        }
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="Helper" value="TestDLL.OracleHelper"/>
  </appSettings>
</configuration>

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL;

namespace 反射Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assmbly = Assembly.Load("TestDLL");
            string helperkey = ConfigurationManager.AppSettings["Helper"];
            IDBHelper helper =(IDBHelper)assmbly.CreateInstance(helperkey);
            helper.Query();
            Console.ReadKey();
        }
    }
}

mian函数或多或少都尚未生成。运行查看结果

图片 4

到了这一个里,笔者早已演示了1个反光应用场景了。其实VS自己就那些地点用了反光。比如。创造对象调用方法时候图片 5VS直接只好帮大家列出那几个目的下的积极分子。那些就是经过反射。其实还有不少。等待我们去发现。反射应该属于C#里头的高级知识点了。如今所说的只是冰山一角。

Ok。讲到那里就得了了哈。

比方刚先河读书的伴儿还有疑难的话,可以评论我们一块儿学学。

只要哪位大牛随便瞄到个谬误,也请告之小编,让自身可以进步。

 

 

相关文章