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领会参数的名称、数据类型、是输入参数还是出口参数,以及参数在章程签名中的地方等。这段话是从大牛的博客拷贝——->传送门

  

下边笔者逐一重点的介绍多少个详细的类。

第1是Assembly。这些存在于System.Reflection命名空间下边。作者第叁讲它的三个加载程序集的的艺术和区分。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
        }
    }
}

以此五个法子语法都很简短。今后以来说那些多少个的区分,和优缺点。

LoadFrom和Load:LoadForm同3个先后集只加载两回,尽管加载了不通的不二法门相同的程序集,他也只可以给你回去在此以前的程序集,LoadFrom只可以用来加载不一样标识的程序集,
约等于唯一的程序集, 不只怕用来加载标识相同但路径差其余程序集。 

LoadFile和LoadForm:loadFile只会加载自己程序集,不会加在其引用的程序集,LoadForm和Load是会加载的其引用程序集。而且LoadFile同2个顺序集只可以加载几次。这几个和LoadForm是同等。

从性质上看
LoadForm没有Load好,功效上也是load强一点。应用的时候如若loadFom和load都满意要求,提出用load。

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

好了我们初始下3个阶段了。程序集将来大家得了。我起来看看程序集里面某个什么?

图片 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();
        }
    }
}

伙伴们方可窥见。我们实例化了1个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的只要添加2个卫冕于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

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

Ok。讲到那里就终止了哈。

假若刚初始学习的同伙还有难题的话,能够评论大家一起学学。

若是哪位大牛随便瞄到个错误,也请告之小编,让自个儿可以进步。

 

 

相关文章