序言:反射(Reflection)是.NET提必要开发者的2个无敌区工作具,就算作为.NET框架的使用者,很多时候不会用到反射。但在局地意况下,越发是在付出1些基础框架或国有类库时,使用反射会使系统架构更灵敏。

引言

反射是.Net提供给大家的一件强力武器,固然超过1/3处境下大家不常用到反射,即便大家兴许也不供给理解它,但对反射的施用作以起先领悟在后来的费用中或许会有所援救。

反射是2个石破惊天的话题,牵扯到的知识点也很多,包含程序集、自定义本性、泛型等,想要完全通晓它不行科学。本文仅仅对反射做2个大意介绍,关于它越来越高深的内容,供给在实践中渐渐控制。本文将分为下面多少个部分介绍.Net中的反射:

  1. 序章,笔者将通过八个例子来引出反射,得到对反射的第二印象。
  2. 反射开端、Type类、反射普通档次。(修改中,近来发表…)
  3. 反射性格(Attribute)。
  4. xxxx (待定)

摘 要

[.net面向对象程序设计进阶]反射(Reflection)利用反射技术实现动态编制程序

 

序章

一经您还未曾接触过反射,而自个儿今后就下一群定义告诉您怎么着是反光,相信您早晚会有一头1棒的感到。作者直接认为那多少个公理式的概念和概念唯有在你足够明白的时候才能较好的发挥功效。所以,我们先来看三个支付中常碰着的题材,再看看怎么着使用反射来消除:

在进展数据库设计的进度中,平时会建立部分基础新闻表,比如说:全国的都会,又可能订单的场地。若是大家将城市的表,起名字为City,它经常包蕴类似这样的字段:

Id     Int Identity(1,1) 城市Id
Name   Varchar(50)           城市称号
ZIP    Varchar(10)           城市邮政编码
… // 略

以此表将供广大任何表引用。若是我们在创造二个商旅预定系统,那么旅舍音信表(Hotel)就会引用此表,用CityId字段来引用酒店所在城市。对于城市(City)表那种状态,表里存放的笔录(城市新闻)是不定的,意思正是说:大家也许随时会向那张表里添加新的都会(当有个别城市的第三家商旅想要参预预定系统时,就需求在City表里新添这家旅社所在的城市)。此时,那样的安排是情理之中的。

反射,2个很有用且妙趣横生的特点。当动态成立有些项指标实例或是调用方法恐怕访问对象成员时平常会用到它,它是根据程序集及元数据而工作的,所以那1章大家来商讨一下程序集、反射如何工作、怎样动态创设类型及对象等辅车相依文化,甚至足以动态创造程序集。

本节导读:本节首要介绍怎样是.NET反射本性,.NET反射能为大家做些什么,最终介绍二种常用的反光的完毕格局,通过对反射性特的摸底,能够设计出格外实用的依据反射的编制程序形式。

在付出中,我们常常会境遇比如有个别处境值在概念好后大约没有改动,那时候使用数据库就显示有个别多余了。首先想到的贰个方法恐怕是在程序中创设八个数组来代表,此时,大家相见了运用数组恐怕带来的首先个难题:不方便使用。当数组结构改变时,恐怕代表全数应用过此数组的地点的目录都发出了改变,那是我们不想见到的。

一.建表及其难点

我们再看看其它一种意况,大家要求标识旅馆预约的情状:未提交、已交由、已撤除、受理中、已退回、已订妥、已过期。此时,很多开发职员会在数据库中创设一张小表,叫做BookingStatus(预约意况),然后将如上意况投入进去,就恍如那样:

金沙注册送58 1

犹如城市(City)表一样,在系统的其余表,比如说客栈订单表(HotelOrder)中,通过字段StatusId引用这几个表来获取酒店预定情形。然则,多少个月现在,即使看上去和都市表的用法1样,结果却发现那个表只在数据库做1道查询恐怕只在先后中调用,却不曾做修改,因为预约流程规定下来后壹般是不会变动的。在应用程序中,也不会给用户提供对那几个表记录的增加和删除改操作界面。

而在先后中调用那一个表时,日常是那种情状:我们须要遵照预约情状对订单列表举办筛选。此时常见的做法是选取多少个下拉菜单(DropDownList),菜单的数据源(DataSource),大家能够很自由地经过三个SqlDataReader得到,大家将DropDownList的文本Text设为Status字段,将值Value设为Id字段。

那时,大家应有已经意识难点:

  1. 设若大家还有航班预定、游船预定,也许其余一些境况,大家需求在数据库中开创很多看似的小表,造成数据库表的数据过多。
  2. 作者们使用DropDownList等控件获取表内容时,供给接二连三到数据库实行询问,潜在地影响属性。

并且,大家也只顾到3点:

  1. 此表1般会在数据库联合查询中选拔到。倘使我们有意味商旅订单的HotelOrder表,它包蕴代表处境的StatusId字段,大家的查询大概会像那样:Select
    *, (Select Status From BookingStatus Where Id =
    HotelOrder.StatusId) as Status From HotelOrder。
  2. 在应用程序中,此表平时作为DropDownList可能其余List控件的数据源。
  3. 其一表大致从未改动。

先是节 应用程序域与程序集

读前不可或缺:

此时,我们能够使用枚举:

二.数组及其难点

发现到如此设计存在难点,大家后天就想办法化解它。我们所想到的第三个格局是足以在先后中开创2个数组来表示预约情况,那样我们就足以删掉BookingStatus状态表(注意能够如此做是因为BookingStatus表的始末规定后差不多从不改动)。

string[] BookingStatus = {  
   “NoUse”,
“未提交”,”已提交”,”已取消”,”受理中”,”已退回”,”已订妥”,”已过期”
};     //
注意数组的0号成分仅仅是起贰个占位成效,以使程序简洁。因为StatusId从一初始。

大家先看它化解了什么样:上边提到的标题一、问题贰都解决了,既不需求在数据库中成立表,又无需三番五次到数据库举行查询。

我们再看看当咱们想要用文件彰显酒馆的订货时,该如何是好(假若有订单类HotelOrder,其性能StatusId代表订单状态,为int类型
)。

// GetItem用于获取3个饭店订单对象, orderId为int类型,代表订单的Id
HotelOrder myOrder = GetItem(orderId);
lbStatus.Text = BookingStatus[myOrder.StatusId]; 
//lbStatus是一个Label控件

近日结束看上去勉强能够,未来我们要求展开贰个操作,将订单的状态改为“受理中”。

myOrder.StatusId = 4;

很不幸,大家发现了运用数组大概带来的首个难题:不方便使用,当我们须求更新订单的情事值时,我们供给去查看BookingStatus数组的定义(除非你耿耿于怀所有情状的数字值),然后依照气象值在数组中的地方来给指标的性质赋值。

金沙注册送58 ,咱俩再看另1个操作,假若某些订单的状态为“已过期”,就要对它实行删减:

if(BookingStatus[myOrder.StatusId]==”已过期”){
    DeleteItem(myOrder);     // 删除订单
}

这会儿的题材和方面包车型地铁切近:大家供给手动输入字符串“已过期”,此时Vs200伍的智能提示发挥不了任何效果,如若大家不幸将情形值记错,大概手误打错,就将导致程序错误,较为稳当的做法如故按下F1贰导向到BookingStatus数组的定义,然后将“已过期”复制过来。

明日,大家再看看怎样来绑定到一个DropDownList下拉列表控件(Id为ddlStatus)上。

ddlStatus.DataSource = BookingStatus;
ddlStatus.DataBind();

然则大家发现发生的HTML代码是这么:

<select name=”ddlStatus” id=”ddlStatus”>
    <option value=”未提交”>未提交</option>
    <option value=”已提交”>已提交</option>
    <option value=”已取消”>已取消</option>
    <option value=”受理中”>受理中</option>
    <option value=”已退回”>已退回</option>
    <option value=”已订妥”>已订妥</option>
    <option value=”已过期”>已过期</option>
</select>

大家看到,列表项的value值与text值相同,那明显不是大家想要的,如何做吧?我们得以给下拉列表写二个数量绑定的事件处理方法。

protected void Page_Load(object sender, EventArgs e) {   
    ddlStatus.DataSource = BookingStatus;
    ddlStatus.DataBound += new EventHandler(ddlStatus_DataBound);
    ddlStatus.DataBind();
}

void ddlStatus_DataBound(object sender, EventArgs e) {
    int i = 0;
    ListControl list = (ListControl)sender;
//注意,将sender转换成ListControl
    foreach (ListItem item in list.Items) {
       i++;
       item.Value = i.ToString();         
    }
}

那样,大家使用数组完结了我们盼望的成效,即使这么落成显得有个别麻烦,固然还设有上边提到的不便宜使用的题材,但那些题目大家耐心细致一点就能战胜,而软件开发差不多根本就未有百分百两全的消除方案,那我们大致就这么好了。

NOTE:在ddlStatus_DataBound事件中,引发风浪的目的sender明显是DropDownList,但是此间却从未将sender转换到DropDownList,而是将它转换到基类型ListControl。那样做是为了越来越好地展开代码重用,ddlStatus_DataBound事件处理方法将不仅仅限于
DropDownList,对于后续自ListControl的别样控件,比如RadioButtonList、ListBox也得以不加改动地使用ddlStatus_DataBound方法。

    假如你对事件绑定还不熟谙,请参考
C#中的委托和事件
一文。

    那里也足以利用Dictionary<String,
Int>来达成,但都留存类似的题目,就不再举例了。

经过本种类的后边章节,大家早已精通,Windows为每一种进程分配独立的内部存款和储蓄器空间地址,各类进度之间不能够直接互动访问。Windows对.NET的支撑是以宿主和COM的花样完成的,基于.NET平台语言实现的代码文件使用Windows
PE的文件格式,CL普拉多其实便是COM,相当于一个虚拟机(当然这么些虚拟机能够布置到自由帮忙它的类别环境中),在安装.NET
Framework时,CLGL450的组件与别的COM壹样在Windows系统中负有平等的待遇,当CL兰德酷路泽运维先导化时会成立三个应用程序域,应用程序域是一组先后集的逻辑容器,它会趁机进度的结束而被卸载销毁,CL景逸SUV把程序代码所急需的次第集加载到近期(或钦赐的)应用程序域内。CL汉兰达能够以其开头化时成立的应用程序域为根基再次创下设别的的新利用程序域,七个利用程序域中的代码不可能直接待上访问,当然能够经过“中介”实行多少传送。新的程序域创设完后CL景逸SUV完全能够卸载它,以联合情势调用AppDomain.Unload方法即可,调用此情势后,CLLX570会挂起如今进程中的全数线程,接着查找并暂停止运输营在将要卸载的程序域内的线程,然后进行垃圾回收,最终主线程复苏运维。

[.net面向对象编制程序基础]类的成员

    public enum BookingStatus
    {
        未提交 =1,
        已提交,
        已取消,
        已定妥 = 6
    }

三.枚举会同难题

不过不幸的事又产生了…
我们的订货程序分成两有的:一部分为B/S端,在B/S端能够拓展饭店订单的
成立(未提交)、提交(已提交)、撤销提交(已撤废),其它还足以见到是否已订妥;一部分为C/S端,为酒馆的订货基本,它可以拓展别的意况的操作。

那时,对于全数体系来说,应该有整个的四个情景。但对于B/S端来说,它唯有未提交、已交由、已收回、已订妥 七个状态,对应的值分别为 一、二、三、六。

作者们回顾一下上边是怎么样行使数组来缓解的,它存在四个毛病:咱俩暗中认可地将订单状态值与数组的索引一一对应地联系了四起。

所以在绑定DropDownList时,我们利用自增的法子来设定列表项的Value值;可能在突显状态时,我们透过lbStatus.Text
= BookingStatus[myOrder.StatusId];
那样的语句来实现。而当那种对应关系被打破时,使用数组的艺术就失效了,因为若是不使用数组索引,大家尚无额外的地方去存款和储蓄状态的数字值。

那时候,大家想到了运用枚举:

public enum BookingStatus {
    未提交 = 1,
    已提交,
    已取消,
    已订妥 = 6
}

作者们想在页面输出三个订单的地方时,能够如此:

HotelOrder myOrder = GetItem(orderId);         //获取3个订单对象
lbStatus.Text = ((BookingStatus)myOrder.StatusId).ToString(); //
输出文本值

大家想翻新订单的图景为 “已交付”:

myOrder.StatusId = (int)BookingStatus.已提交;

当状态为“已撤除”时大家想实行有些操作:

if(BookingStatus.已取消 == (BookingStatus)myOrder.StatusId){
    // Do some action
}

此时,VS 200伍的智能提醒已经可以表明完全意义,当我们在BookingStatus后按下“.”时,能够体现出装有的场地值。

NOTE:当大家运用枚举存款和储蓄状态时,myOrder对象的StatusId最棒为BookingStatus枚举类型,而非int类型,那样操作会尤其便利1些,但为了和前边使用数组时的情事保持统一,那里StatusId仍接纳int类型。

如上两种情形选用枚举都显得十一分的流利,直到大家供给绑定枚举到DropDownList下拉列表的时候:大家明白,能够绑定到下拉列表的有两类对象,一类是兑现了IEnumerable接口的可枚举集合,比如ArrayList,String[],List<T>;1类是兑现了IListSource的数据源,比如DataTable,DataSet。

NOTE:实际上IListSource接口的GetList()方法重临八个IList接口,IList接口又继续了IEnumerable接口。因而看来,IEnumerable是贯彻可枚举集合的底子,在作者翻译的一篇小说
C#中的枚举器
中,对那几个核心做了详实的座谈。

可大家都了解:枚举enum是一个宗旨项目,它不会促成任何的接口,那么咱们下去该如何是好呢?

其余Windows程序都得以寄宿CL卡宴,一台机上能够设置四个本子的CLLAND。Windows在开发银行二个托管的次序时会先运维MSCorEE.dll中的一个办法,该办法在里头依据3个托管的可执行文件消息来加载相应版本的CL奇骏,CLHighlander早先完成之后,将次第集加载到使用程序域,最终CLR检查程序集的CL冠道头消息找到Main方法并实施它。

1.什么是.NET反射?

在事实上使用中,也许需求用户下拉挑选那个情状值,这时就要求大家把枚举绑定到下拉框上(此处以Combobox为例)了。大家领会,能够绑定到下拉框列表的有三种类型:壹种是落到实处了IEnumerable接口的可枚举类型,比如ArrayList,String[],List<T>;一类是兑现了IListSource的数据源,比如DataTable,DataSet。

四.选用反射遍历枚举字段

最笨也是最简便的法子,我们得以先成立二个GetDataTable方法,此措施依照枚举的字段值和数字值塑造三个DataTable,最终回到这一个创设好的DataTable:

  private static DataTable GetDataTable() {
     DataTable table = new DataTable();
     table.Columns.Add(“Name”, Type.GetType(“System.String”));      
//创建列
     table.Columns.Add(“Value”, Type.GetType(“System.Int32”));      
//创建列

     DataRow row = table.NewRow();
     row[0] = BookingStatus.未提交.ToString();
     row[1] = 1;
     table.Rows.Add(row);

     row = table.NewRow();
     row[0] = BookingStatus.已提交.ToString();
     row[运用反射将枚举绑定到下拉框,中的反射。1] = 2;
     table.Rows.Add(row);

     row = table.NewRow();
     row[0] = BookingStatus.已取消.ToString();
     row[1] = 3;
     table.Rows.Add(row);

     row = table.NewRow();
     row[0] = BookingStatus.已订妥.ToString();
     row[1] = 6;
     table.Rows.Add(row);

     return table;
 }

接下去,为了方便使用,我们再次创下造一个特地使用这几个DataTable来设置列表控件的不二等秘书诀SetListCountrol():

// 设置列表
 public static void SetListControl(ListControl list) {
     list.DataSource = GetDataTable();      // 获取DataTable
     list.DataTextField = “Name”;
     list.DataValueField = “Value”;
     list.DataBind();
 }

明日,我们就足以在页面中如此去将枚举绑定到列表控件:

protected void Page_Load(object sender, EventArgs e)
{
    SetListControl(ddlStatus);   // 尽管页面中已有ID为ddlStatus
的DropDownList
}

万一持有的枚举都要通过那样去绑定到列表,我以为还不及在数据库中平素建表,那样其实是太费力了,而且大家是依据枚举的公文和值去HardCoding出贰个DataTable的:

DataRow row = table.NewRow();
row[0] = BookingStatus.未提交.ToString();
row[1] = 1;
table.Rows.Add(row);

row = table.NewRow();
row[0] = BookingStatus.已提交.ToString();
row[1] = 2;
table.Rows.Add(row);

row = table.NewRow();
row[0] = BookingStatus.已取消.ToString();
row[1] = 3;
table.Rows.Add(row);

row = table.NewRow();
row[0] = BookingStatus.已订妥.ToString();
row[1] = 6;
table.Rows.Add(row);

本条时候,大家想有未有主意通过遍历来促成那里?借使想要遍历那里,首先,我们必要贰个蕴含枚举的各类字段音信的指标,那些指标至少含有两条新闻,1个是字段的文件(比如“未提交”),三个是字段的数字型值(比如一),咱们一时半刻管那么些目的叫做田野(field)。其次,应该存在贰个可遍历的、蕴涵了字段音信的指标(也等于filed)
的聚合,大家一时管这么些集合叫做enumFields。

那么,下面就足以这么去贯彻:

foreach (xxxx field in enumFields)
{
    DataRow row = table.NewRow();
    row[0] = 田野先生.Name;         // 杜撰的属性,代表
文本值(比如“未提交”)
    row[1] = filed.intValue;     // 杜撰的属性,代表 数字值(比如一)

    table.Rows.Add(row);
}

那段代码很不完全,我们注意到
xxxx,它应该是包裹了字段音信(大概叫元数据metadata)的目标的花色。而对此enumFields,它的档次应该是xxxx这一个类别的聚集。那段代码是我们依据思路假想和演绎出来的。实际上,.Net
中提供了 Type类 和 System.Reflection命名空间来扶助化解我们今后的标题。

本身在背后将较详细地介绍
Type类,以往只盼望您能对反射有个第一印象,所以只简单地作以表明:Type抽象类提供了走访类型元数据的能力,当你实例化了一个Type对象后,你能够透过它的属性和艺术,获取项指标元数据消息,或许进一步取得该类型的成员的元数据。留意到那边,因为Type对象总是基于某一品类的,并且它是1个抽象类,故此大家在开创Type类型时,必供给提供
类型,也许项指标实例,也许项指标字符串值(Part.二会表达)。

始建Type对象有很各类格局,本例中,大家选取typeof操作符来展开,并传递BookingStatus枚举:

Type enumType = typeof(BookingStatus);

接下来,大家相应想艺术获得 封装了字段音信的对象 的集结。Type类提供
GetFields()方法来实现这一进程,它回到二个 FieldInfo[]
数组。实际上,相当于地方大家enumFields集合的品种。

FieldInfo[] enumFields = enumType.GetFields();

今后,我们就足以遍历那1汇聚:

foreach (FieldInfo field in enumFields)
{
    if (!field.IsSpecialName)
    {
       DataRow row = table.NewRow();
       row[0] = 田野(field).Name;     // 获取字段文本值
       row[1] = Convert.ToInt32(myField.GetRawConstantValue()); //
获取int数值
       table.Rows.Add(row);
    }
}

那里田野同志的Name属性获取了枚举的文书,GetRawConstantValue()方法获得了它的int类型的值。

大家看1看完整的代码:

private static DataTable GetDataTable() {

     Type enumType = typeof(BookingStatus);    // 创制项目
     FieldInfo[] enumFields = enumType.Get菲尔德s();   
//获取字段音信目的集合

     DataTable table = new DataTable();
     table.Columns.Add(“Name”, Type.GetType(“System.String”));
     table.Columns.Add(“Value”, Type.GetType(“System.Int32”));
    // 遍历集合
     foreach (FieldInfo field in enumFields) {
        if (!field.IsSpecialName) {
            DataRow row = table.NewRow();
            row[0] = field.Name;
            row[1] = Convert.ToInt32(field.GetRawConstantValue());
            //row[1] = (int)Enum.Parse(enumType, 田野(field).Name);
//也能够这样

            table.Rows.Add(row);
        }
     }

     return table;
 }

留意,SetListControl()方法照旧留存并实用,只是为着省去篇幅,小编从未复制过来,它的接纳和事先是一律的,大家只是修改了GetDataTable()方法。

 

反射是.NET一个重要的本性,《CL揽胜极光viaC#》一书中对.NET反射的解释为:在大家应用程序中使用元数据来代表存款和储蓄。编写翻译程序集或模块时,编写翻译器会创建二个门类定义表、三个字段定义表、3个措施定义表以及其它表。而大家只要想动态调用那一个元数据表,或视为为那个元数据创设1个指标模型,那些进度就是反光。

而是,枚举enum是三个着力类型,它不会落到实处其余的接口,鲜明,不能直接将枚举绑定到下拉框上,那么应该使用什么方法呢?

5.行使泛型来实现代码重用

着眼地点的代码,假设大家未来有另三个枚举,叫做TicketStatus,那么大家要将它绑定到列表,大家唯一供给改变的正是那里:

Type enumType = typeof(BookingStatus); //将BookingStatus改作TicketStatus

既是那样,我们何不定义3个泛型类来开始展览代码重用呢?大家管那么些泛型类叫做EnumManager<TEnum>。

public static class EnumManager<TEnum>
{
    private static DataTable GetDataTable()
    {
       Type enumType = typeof(TEnum);  // 获取项目对象
       FieldInfo[] enumFields = enumType.GetFields();

       DataTable table = new DataTable();
       table.Columns.Add(“Name”, Type.GetType(“System.String”));
       table.Columns.Add(“Value”, Type.GetType(“System.Int32”));
       //遍历集合
       foreach (FieldInfo field in enumFields)
       {
           if (!field.IsSpecialName)
           {
               DataRow row = table.NewRow();
              row[0] = field.Name;
              row[1] = Convert.ToInt32(field.GetRawConstantValue());
              //row[1] = (int)Enum.Parse(enumType, 田野先生.Name);
也足以如此

              table.Rows.Add(row);
           }
       }
       return table;
    }

    public static void SetListControl(ListControl list)
    {
       list.DataSource = GetDataTable();
       list.DataTextField = “Name”;
       list.DataValueField = “Value”;
       list.DataBind();
    }
}

OK,现在总体都变得简便的多,未来,我们再供给将枚举绑定到列表,只要这么就行了(ddl开始的是DropDownList,rbl先河的是RadioButtonList):

EnumManager<BookingStauts>.SetListControl(ddlBookingStatus);
EnumManager<TicketStatus>.SetListControl(rblTicketStatus);

NOTE:如若你对泛型素不相识,请参阅 C#
中的泛型
一文。下边的兑现并从未设想到质量的题材,仅仅为了引出反射使用的八个实例。

第壹节 加载程序集

简单易行通俗的说,正是动态调用编写翻译过的主次集中的品质,字段,方法等的进度,就是反光。

 

六 .Net 中反射的贰个范例。

任由是VS2005的智能提示,依旧修改变量名时的重构成效,都施用了反光成效。在.Net
FCL中,也时常能观察反射的影子,那里就向大家演示贰个最常见的例证。我们明白,在CLSportage中总括有三种档次,1种是值类型,一种是引用类型。声雅培(Abbott)(Dumex)个引用类型的变量并对项目实例化,会在应用程序堆(Application
Heap)上分配内部存款和储蓄器,创立对象实例,然后将指标实例的内部存款和储蓄器地址再次回到给变量,变量保存的是内部存款和储蓄器地址,实际约等于一个指南针;声圣元个值类型的实例变量,则会将它分配在线程堆栈(Thread
Stack)上,变量本身带有了值类型的具备字段。

今日假如大家必要相比较四个目的是不是等于。当大家相比较多个引用类型的变量是或不是等于时,大家比较的是那多个变量所指向的是否堆上的同1个实例(内部存款和储蓄器地址是不是相同)。而当我们比较八个值类型变量是不是等于时,如何做啊?因为变量本人就带有了值类型全部的字段(数据),所以在可比时,就必要对四个变量的字段实行各个的十分的可比,看看各类字段的值是不是都十三分,要是其余几个字段的值不等,就回去false。

事实上,执行那样的三个比较并不须求大家团结编排代码,Microsoft已经为大家提供了贯彻的方法:全体的值类型继承自
System.ValueType, ValueType和全数的体系都无冕自System.Object
,Object提供了一个Equals()方法,用来判定四个对象是或不是等于。不过ValueType覆盖了Object的Equals()方法。当我们比较五个值类型变量是不是等于时,能够调用继承自ValueType类型的Equals()方法。

public struct ValPoint {
    public int x;
    public int y;
}
static void Main(string[] args) {
    bool result;

    ValPoint A1;
    A1.x = A1.y = 3;

    ValPoint B1 = A1;            // 复制A的值给B
    result = A1.Equals(B1);
    Console.WriteLine(result);      // 输出 True;
}

您有未有想到当调用Equals()方法时会发生什么事呢?前面大家早已涉嫌假若是值类型,会对多个变量的字段举办依次的比较,看看每一个字段的值是或不是都等于,可是什么获取变量的装有字段,遍历字段,并相继比较呢?此时,你应该发现到又到了用到反射的时候了,让大家利用reflector来查阅ValueType类的Equals()方法,看看微软是怎么办的吗:

public override bool Equals(object obj) {
    if (obj == null) {
       return false;
    }
    RuntimeType type = (RuntimeType)base.GetType();
    RuntimeType type2 = (RuntimeType)obj.GetType();
    if (type2 != type) {
       return false;
    }
    object a = this;
    if (CanCompareBits(this)) {
       return FastEqualsCheck(a, obj);
    }
    // 获取具有实体字段
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Instance);
    // 遍历字段,判断字段值是或不是等于
    for (int i = 0; i < fields.Length; i++) {
       object obj3 = ((RtFieldInfo)fields[i]).InternalGetValue(a,
false);
       object obj4 = ((RtFieldInfo)fields[i]).InternalGetValue(obj,
false);
       if (obj3 == null) {
           if (obj4 != null) {
              return false;
           }
       } else if (!obj3.Equals(obj4)) {
           return false;
       }
    }
    return true;
}

只顾到上边加注释的那两段代码,能够看到当对值变量进行比较时,是会动用反射来促成。反射存在着品质不佳的题材(不仅如此,还留存着累累的装箱操作),简而言之,在值类型上调用Equals()方法开发是会相当大的。但是这一个事例仅仅为了求证反射的用途,我想已经达到规定的标准了目标。上面包车型大巴代码不能一心领会也不妨,后边会再涉及。

程序集是负有类型的聚合,它还有1个器重的东西正是元数据。JIT就是行使程序集的TypeRef和AssemblyRef等元数据来鲜明所引用的先后集及项目,那些元数据蕴含名称、版本、语言文化和公钥标记等,JIT正是依据那一个消息来加载三个先后集到利用程序域中。假如要自身加载2个程序集,能够调用类型Assembly的LoadXXX种类措施。

反射在.NET,通过System.Reflection命名空间中的类来促成。

行使反射遍历枚举字段

7.小结

见到这里,你应有对反射有了八个起来的定义(可能叫反射的多个用途):反射是一种普遍的叫法,它通过
System.Reflection 命名空间 并 协作 System.Type
类,提供了在运维时(Runtime)对于 类型和对象(及其成员)的大旨音信 以及
元数据(metadata)的拜访能力。

 

(壹) Load重载连串

二.反光能为大家做些什么?

要遍历枚举,首先就供给2个富含枚举各样字段新闻的指标,这么些指标至少应当包蕴五个性情,三个是字段的名称,一个是字段的值,以造福后续绑定。

该方法会依照一定的顺序查找钦命目录中的程序集:先去GAC中检索(借使是3个强命名程序集),要是找不到,则去应用程序的基目录、子目录查找。即使都没找到,则抛出特别。如下代码加载程序集MyAssemblyB:

本条题材是大家学习反射的根本,总得知道学习它的益处,才会三番五次把本文看下来。

先看下完整的代码:

            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);

反射天性,确实是.NET三个要命首要且实用的特征。

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.DataSource = GetDataTable();
            comboBox1.DisplayMember = "Name";
            comboBox1.ValueMember = "Value";
        }

      public static DataTable GetDataTable()
        {
            Type t = typeof(BookingStatus);  //创建类型
            FieldInfo[] fieldinfo = t.GetFields(); //获取字段信息对象集合

            DataTable table = new DataTable();
            table.Columns.Add("Name", typeof(String));
            table.Columns.Add("Value", typeof(Int32));

            foreach (FieldInfo field in fieldinfo)
            {
                if (!field.IsSpecialName)
                {
                    DataRow row = table.NewRow();
                    row[0] = field.Name;   //获取文本字段
                    row[1] = (int)field.GetRawConstantValue();  //获取int数值
                    table.Rows.Add(row);
                }
            }
            return table;
        }
    }

    public enum BookingStatus
    {
        未提交 =1,
        已提交,
        已取消,
        已定妥 = 6
    }

(二) LoadFrom重载体系

A.枚举类型成员

 

加载钦定程序集名称或路径的程序集,其在里头调用Load方法,并且还是能钦定二个互联网路径,即便内定互连网路径,则先下载该程序集,再将其加载到程序域,如下代码:

B.实例化新对象

效果:金沙注册送58 2

Assembly.LoadFrom("http://solan.cnblogs.com/MyAssembly.dll");

C.执行对象成员

此地大致做八个表明:Type抽象类提供了走访类型元数据的能力,当实例化了3个Type对象后,可以经过它的习性和章程,获取项指标元数据的消息,只怕进一步赢得该项目标分子的元数据信息。注意到那边,因为Type对象总是基于某壹实际品种的,并且它是二个抽象类,所以再次创下立Type类型时,需求提供品类名称或许项指标实例。程序集元数据,通过Type类型就能够访问类型的元数据音信,而访问类型元数据的操作,就叫做反射。

(叁) LoadFile重载连串

D.查找类型音讯

 

从随机路径加载二个程序集,并且能够从不一致途径加载相同名称的次序集。

E.查询程序集信息

运用泛型来完成代码重用

在一个类别中,恐怕程序集以内都有依靠关系,也足以将一个主次集作为能源数量嵌入到1个程序集中,在急需时再加载该程序集,那时通过注册ResolveAssembly事件来加载这么些顺序集。如下;

F.检查选取于某系列型的自定义特性

着眼地方的代码,假使未来有另一个枚举,叫做TicketStatus,那么要将它的枚举项文件和值转换为DataTable,唯壹需求变更的正是那里:

金沙注册送58 3

G.创设和编写翻译新的程序集

Type t = typeof(BookingStatus); //将枚举名称更换
            AppDomain.CurrentDomain.AssemblyResolve += (sender, arg) =>
            {
                byte[] buffer = null;
                using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApp.MyAssemblyA.dll"))
                {
                    buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);
                }
                return Assembly.Load(buffer);
            };

H.简化执行时而非编写翻译时绑定的数码的操作。(C#四.0之后新效率)

既是那样,就足以行使泛型来兑现代码的录用,将回到DataTable的措施更改为泛型方法:

金沙注册送58 4

此外.NET新本子中允许泛型上的反射.

     public static DataTable GetDataTable<T>()
        {
            Type t = typeof(T);  //创建类型
            FieldInfo[] fieldinfo = t.GetFields(); //获取字段信息对象集合

            //...............省略            

            return table;
        }

以上代码须求必须先将MyAssemblyA.dll文件以财富情势嵌入到ConsoleApp项目中。那样在运作ConsoleApp程序时,假使采取了MyAssemblyA中的类型且未找到MyAssemblyA.dll文件,则会进入上面包车型地铁轩然大波措施来加载程序集MyAssemblyA。

如上是反射的中坚天性,参考了《C#本质论》和《C#高级编制程序》

从以上代码能够看来,综合应用反射,泛型等技术,可以不小地提升代码的八面玲珑,可重用性。

比方只是想明白3个程序集的元数据解析其连串而不调用类型的积极分子,为了提高品质,可以调用这几个方法:

听说上面包车型地铁为主特征,大家能够设计出广大丰盛实用的编制程序方式。

 

Assembly.ReflectionOnlyLoadFrom(String assemblyFile)
Assembly.ReflectionOnlyLoad(byte[] rawAssembly)
Assembly.ReflectionOnlyLoad(String assemblyName)

上面罗列三种基于反射设计形式下的实例:

万一准备调用上边这多个方法加载的次第集中类型的代码,则CLR会抛出分外。

A.利用反射创动态创建程序集的API文书档案。基于反射允许枚举程序集中类型及成员的特色,我们可以通过反射获取已编写翻译的主次集中的字段方法属性事件和他们的XML注释。从而动态创建程序集的API文档;

 

B.非时不时用的反光工厂情势。反射工厂情势在设计形式中相比较便于了然,也比较简单。很多代码生成器中就使用那种设计形式实现分歧数据库的反光调用。比如我们有MsSql、MySql、Oracle那三种数据库,在项目规划中,大家有非常的大或者随时换另1种数据库,因而必要同时落到实处那三种数据库的功底增加和删除改查的类即数据访问类。我们要切换数据库的时候,只供给在config中改变数据库类型,其余的办事付出反射工厂类去动态调用编译好的先后集中对应的数据库访问方法。

第三节 反射

设若未有清楚也没涉及,那里只是说Bellamy下反光的运用实例,以便于更有信心的就学反射。反射在设计形式中的应还有不少,那里不再列举。

咱们通晓,在程序集(或模块)内有二个很主要的数码就是元数据,它们描述了花色定义表,字段定义表,方法表等,也正是说全体的项目及成员定义项都会在此间被掌握详细地记录下来。很分明,若是大家获得了这个“描述新闻”,当然就一定于已经明朗精通了多少个类型及其成员,进而就能够“构造”那么些种类,通过反射就足以达到如此的目的。另人喜欢的是咱们不用分析这几个元数据就能够便宜地获取程序集内的档次成员,.NET
Framework提供了部分与此相关的类定义在命名空间System.Reflection下。

三.反光应用基础

反射提供了包装程序集、模块和花色的对象(Type
类型)。反射机制运转在程序运转时动态发现项目及其成员。

地方说了如此多,无非就是先让大家知晓反射能为大家做些什么,下边进入正题,说一下反光的代码达成。

(一)查找程序集内所定义的品种

上边首要介绍反射的宗旨类及类成员

在将某一程序集加载到使用程序域后,能够经过Assembly的GetExportedTypes方法来收获该程序集全体的精晓类型,如下代码:

反射的命名空间:System.Reflection

金沙注册送58 5

反射的类大多都在这么些命名空间中。

        private void GetTypes()
        {
            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);
            Type[] types = assembly.GetExportedTypes();
            foreach (Type t in types)
            {
                Console.WriteLine(t.Name);
            }
        }

关键的类:System.Type

金沙注册送58 6

其1类是反光的着力,其属性方法能够收获周转时的音信。

(二)查找类型成员

Type类派生于System.Reflection.MemberInfo抽象类

在命名空间System.Reflection中有四个虚幻类型MemberInfo,它包裹了与项目成员相关的通用属性,每多少个项目成员都有一个对应的从MemberInfo派生而来的品种,并且放置了某些特种的习性特征,如FieldInfo、MethodBase(ContructorInfo、MethodInfo)、PropertyInfo和伊夫ntInfo。能够经过调用类型Type对象的GetMembers方法得到该类型的持有成员或相应成员,如下代码(对地方的GetTypes方法的改动)获取全体成员列表:

MemberInfo类中的只读属性

            Type[] types = assembly.GetExportedTypes();
            foreach (Type t in types)
            {
                Console.WriteLine(t.Name);
                MemberInfo[] members = t.GetMembers();
            }

属性

Type有一组GetXXX方法是取得对象成员的,以下列出部分办法:

描述

GetConstructor/GetConstructors //获取构造函数
GetEvent/GetEvents //获取事件
GetField/GetFields //获取字段
GetMethod/GetMethods //获取方法
GetProperty/GetProperties //获取属性

备注

还要各样方法都足以选择1个枚举类型BindingFlags的参数内定控制绑定和由反射执行的分子和类型搜索方法的标志。有关BindingFlags
枚举可参考MSDN文档.aspx%E3%80%82)

TypeDeclaringType

如下代码获取奥迪Car类型的Owner属性和Run()方法:

赢得评释该成员的类或接口的门类

金沙注册送58 7

MemberTypesMemberType

        private void GetTypeMethod()
        {
            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);
            Type t = assembly.GetType("MyAssemblyB.AudiCar");
            MethodInfo method = t.GetMethod("Run");
            PropertyInfo pro = t.GetProperty("Owner");
        }

获得成员的花色,那么些值用于提示该成员是字段、方法、属性、事件、或构造函数

金沙注册送58 8

那是三个枚举,它定义了用于表示差别成员的类型值。这么些值包含:MemberTypes.Constructor,MemberTypes.Method,MemberTypes.Field,MemberTypes.伊夫nt,MemberTypes.Property。因而可以透过检查MemberType属性来规定成员的档次,例如,在MemberType属性的值为MemberTypes.Method时,该成员为艺术

(三)构造类型实例

IntMetadataToken

在得到品种及成员音信之后,大家就足以构造类型的实例对象了。FCL提供了多少个法子来协会多个品类的实例对象,有关那几个办法详细内容,可参看MSDN文书档案:

赢得与一定元数据相关的值

Activator.CreateInstance() //重载系列
Activator.CreateInstanceFrom() //重载系列
AppDomain.CurrentDomain.CreateInstance() //重载系列
AppDomain.CurrentDomain.CreateInstanceFrom() //重载系列

ModuleModule

如下构造奥迪(Audi)Car类型的实例:

赢得三个意味着反射类型所在模块的Module对象

金沙注册送58 9

StringName

        private void TestCreateInstance()
        {
            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);
            Type t = assembly.GetType("MyAssemblyB.AudiCar");
            var obj = Activator.CreateInstance(t);
            Debug.Assert(obj != null);
        }

成员的名目

金沙注册送58 10

TypeReflectedType

看一下调节和测试:

反射的指标类型

金沙注册送58 11

Type类的只读属性

除此以外,还足以调用类型的构造函数创设实例对象,如下:

属性

obj = t.InvokeMember("AudiCar", BindingFlags.CreateInstance, null, null, null);

描述

 

AssemblyAssembly

第伍节 通过反射访问对象成员

得到钦定项目标顺序集

若是只是获得类型的目的,好像意义并很小,大家越多的是要操作对象,比如访问属性,调用方法等,那1节大家来看一下怎么访问成员。

TypeAttributesAttributes

种类Type提供了一个走访目的项目成员的相当可相信的主意InvokeMember,调用此办法时,它会在项目成员中找到对象成员(那一般钦定成员名称,也足以钦赐搜索筛选标准BindingFlags,倘使调用的对象成员是艺术,还是能够给艺术传递参数。),要是找到则调用目的措施,并回到目的访问归来的结果,假诺未找到,则抛出格外,假诺是在对象措施内部有非常,则InvokeMember会先捕获该尤其,包装后再抛出新的相当TargetInvocationException。以下是InvokeMember方法的原型:

取得制定项指标特征

金沙注册送58 12

TypeBaseType

public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args);
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args,
 CultureInfo culture);
public abstract object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
 object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters);
name 目标方法名称
invokeAttr 查找成员筛选器
binder 规定了匹配成员和实参的规则
target 要调用其成员的对象
args 传递给目标方法的参数

赢得钦赐项目标直接基类型

金沙注册送58 13

StringFullName

在上一节的末尾大家来得了怎么着调用类型的构造函数来实例化1个指标,下边包车型客车代码演示了何等调用对象的艺术,在那之中措施Turn接收3个Direction类型的参数:

获得内定项目标人名

            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);
            Type t = assembly.GetType("MyAssemblyB.AudiCar");
            var obj = Activator.CreateInstance(t);
            t.InvokeMember("Turn", BindingFlags.InvokeMethod, null, obj, new object[] { Direction.East });

boolIsAbstract

除此以外,调用指标对象的法门,还足以以MethodInfo的章程开始展览,如下:

如若钦点项目是抽象类型,重临true

            Type t = assembly.GetType("MyAssemblyB.AudiCar");
            var obj = Activator.CreateInstance(t);
            MethodInfo method = t.GetMethod("Turn");
            method.Invoke(obj, new object[] { Direction.Weast });

boolIsClass

以下是对品质的读写操作:

一经钦赐项目是类,再次回到true

            Type t = assembly.GetType("MyAssemblyB.AudiCar");
            var obj = Activator.CreateInstance(t);
            //为属性Owner赋值
            obj.GetType().GetProperty("Owner").SetValue(obj, "张三", null);
            //读取属性Owner的值
            string name = (string)obj.GetType().GetProperty("Owner").GetValue(obj, null);

stringNamespace

对于其余成员(如字段等)的拜访,可参照MSDN文书档案。

获取钦点项指标命名空间

反射对泛型的扶助

Type类的点子

上述的以身作则都以本着普通品种,其实反射也提供了对泛型的支撑,那里只简不难单演示一下反光对泛型的简便操作。比如我们有如下1个泛型类型定义:

方法

金沙注册送58 14

描述

namespace MyAssemblyB
{
    public class MyGeneric<T>
    {
        public string GetName<T>(T name)
        {
            return "Generic Name:" + name.ToString();
        }
    }
}

ConstructorInfo[]GetConstructors()

金沙注册送58 15

取得内定项目标构造函数列表

那些类型很简短,类型MyGeneric内有一个模式,该措施再次来到带有附加消息”
Generic Name:”的名目。先来看一下哪些获得钦赐参数类型为string的泛型类:

EventInfo[]GetEvents();

金沙注册送58 16

收获钦命项目标日子列

        private void TestGenericType()
        {
            string assemblyName = "MyAssemblyB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            Assembly assembly = Assembly.Load(assemblyName);
            Type[] types = assembly.GetExportedTypes();
            foreach (Type t in types)
            {
                //检测是否泛型(在程序集MyAssemblyB中只定义了一个泛型类型 MyGeneric<T>)
                if (t.IsGenericType)
                {
                    //为泛型类型参数指定System.String类型,并创建实例
                    object obj = Activator.CreateInstance(t.MakeGenericType(new Type[] { typeof(System.String) }));
                    //生成泛型方法
                    MethodInfo m = obj.GetType().GetMethod("GetName").MakeGenericMethod(new Type[] { typeof(System.String) });
                    //调用泛型方法
                    var value = m.Invoke(obj, new object[] { "a" });
                    Console.WriteLine(value);
                }
            }
        }

FieldInfo[]GetFields();

金沙注册送58 17

得到内定项指标字段列

调节起来,看一下末尾的value值:

Type[]GetGenericArguments();

金沙注册送58 18

获得与已布局的泛型类型绑定的项目参数列表,假诺内定项目标泛型类型定义,则赢得类型形参。对徐婧早布局的花色,该列表就大概还要涵盖类型实参和类型形

反射泛型的时候,要先明确目的项目是泛型,在制造泛型类型实例前,必须调用MakeGenericType方法组织2个着实的泛型,该方法接收3个要内定泛型类型参数的种类数组,同样调用泛型方法前要调用方法MakeGenericMethod构造相应的泛型方法,此格局也接到贰个内定泛型类型的类型数组。

MethodInfo[]GetMethods();

 

获取钦赐项指标不贰秘籍列表

第伍节 动态创制类型

PropertyInfo[]GetProperties();

前方几节所描述的都以依照已经存在程序集的情事下展开反射,.NET
Framework还提供了在内部存款和储蓄器中动态创设类型的雄强功用。大家知晓程序集包蕴模块,模块包蕴项目,类型包括成员,在动态创造类型的时候也是要规行矩步那几个顺序。动态创立类型是根据元数据的兑现格局来兑现的,那1某个被定义在命名空间System.Reflection.Emit内,有1层层的XXXBuilder构造器来创设相应的品种对象。大家来看壹要动态创设类型,有何样步骤(那里只是简单演示):

获取钦点项指标属性列表e

(一) 程序集是老窝,所以要先创立一个先后集:

MemberInfo[]GetMembers();

AssemblyBuilder aBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("TempDynamicAssembly"), AssemblyBuilderAccess.Run);

获取钦定项指标分子列表

(二) 有了程序集,接下去是模块

反射还有不少类,那里不一一介绍,详细能够查看MSDN:

ModuleBuilder mBuilder = aBuilder.DefineDynamicModule("NotifyPropertyChangedObject");

(三) 接下来正是创造项目了:

四.反射实例

this.tBuilder = mBuilder.DefineType(typeFullName, TypeAttributes.Public | TypeAttributes.BeforeFieldInit);

上面通过多少个实例来上学一下反光最核心的选用办法。

(肆)
未来能够缔造项目标成员了,为品种创造3特性情Name。大家知晓属性蕴含字段和对字段的八个访问器,所以应该先成立字段,然后再成立四个访问器方法,那壹段是遵从IL码的先后顺序来的,如下:

创制一个消除方案,包括五个品种,项目ClassLibrary生成三个DLL,另一个档次是ReflectionTestGet,用于反射调用类ClassLibrary

金沙注册送58 19

金沙注册送58 20

            FieldBuilder fieldBuilder = this.tBuilder.DefineField(string.Format("{0}Field", propertyName), propertyType, FieldAttributes.Private);
            PropertyBuilder propertyBuilder = tBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            MethodBuilder getAccessor = tBuilder.DefineMethod(string.Format("get_{0}", propertyName), getSetAttr, propertyType, Type.EmptyTypes);
            ILGenerator getIL = getAccessor.GetILGenerator();
            getIL.Emit(OpCodes.Ldarg_0);
            getIL.Emit(OpCodes.Ldfld, fieldBuilder);
            getIL.Emit(OpCodes.Ret);
            propertyBuilder.SetGetMethod(getAccessor);

            MethodBuilder setAccessor = tBuilder.DefineMethod(string.Format("set_{0}", propertyName), getSetAttr, null, new Type[] { propertyType });
            setAccessor.DefineParameter(1, ParameterAttributes.None, "value");
            ILGenerator setIL = setAccessor.GetILGenerator();
            setIL.Emit(OpCodes.Nop);
            setIL.Emit(OpCodes.Ldarg_0);
            setIL.Emit(OpCodes.Ldarg_1);
            setIL.Emit(OpCodes.Stfld, fieldBuilder);
            setIL.Emit(OpCodes.Ldarg_0);
            setIL.Emit(OpCodes.Ldstr, propertyName);
            setIL.Emit(OpCodes.Call, this.mBuilder);
            setIL.Emit(OpCodes.Nop);
            setIL.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setAccessor);

第10个品类的三个类如下:

金沙注册送58 21

MartialArtsMaster.cs

瞩目,那之中有对事件的操作,能够忽略。

金沙注册送58 22金沙注册送58 23

(五) 最终调用类型构造器的CreateType()方法就足以创建该项目了:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ClassLibrary{    /// <summary>    /// 类:武林高手    /// MartialArtsMaster    /// </summary>    class MartialArtsMaster    {        /// <summary>        /// 级别        /// </summary>        public int _level = 9;        /// <summary>        /// 编号        /// </summary>        public int Id { get; set; }        /// <summary>        /// 姓名        /// </summary>        public string Name { get; set; }        /// <summary>        /// 年龄        /// </summary>        public int Age { get; set; }        /// <summary>        /// 门派        /// </summary>        public string Menpai { get; set; }        /// <summary>        /// 武学        /// </summary>        public string Kungfu { get; set; }        /// <summary>        /// 级别        /// </summary>        public int Level        {            get            {                return _level;            }            set            {                _level = value;            }        }        /// <summary>        /// 攻击        /// </summary>        /// <param name="kungfu"></param>        /// <returns></returns>        public string Attack(string kungfu)        {            return "使用用了功夫:" + kungfu;        }        public string Kill(string kungfu, string name)        {            return "使用用了功夫:" + kungfu + "击杀了" + name;        }    }}
tBuilder.CreateType();

View Code

该方法再次来到1个Type类型。

Person.cs

花色创立完毕后,我们就能够利用上一节讲的反光相关文化对该项目进行操作了,那里当然是3个归纳的品类,借使想创设复杂的类型,比如有措施,事件等成员,那能够发挥您的汇编能力来日趋折腾吗,也能够体会一下立即汇编制程序序员们的苦逼!托管下的汇编编码已经很简化了,围绕Emit方法折腾死!若是想钻探IL,能够用IL
DASM打开托管程序集,稳步欣赏吧。

金沙注册送58 24金沙注册送58 25

在大家的不足为奇费用中,有时用了动态类型大概很有利的,比如当您要创造一个DataGrid的数量源DataTable,但多少列不分明,列的数据类型不明确,列名也不明显的情形下,这时依据必要创造1个动态类型,继而更创立三个该品种的聚众就很方便使用了。小编封装了一个动态创制类型的类,在本文的尾声提供下载,喜欢的能够拿去。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ClassLibrary{    /// <summary>    /// 类:人    /// </summary>    class Person    {        public string gender { get; set; }        public string race { get; set; }        public string Country { get; set; }        public string Eat(string strCountry)        {            switch (strCountry)            {                case "美国":                    return "爱吃西餐";                case "韩国":                    return "爱吃泡菜";                default:                    return "不知道";            }        }    }}

那里所描述的是动态地在内部存款和储蓄器创制一个类,关于动态类型dynamic和var,那里就不再瞎掰了,感兴趣的能够去寻找有关资料。

View Code

 

第一个档次调用如下:

第陆节 应用反射时要留心的几点

金沙注册送58 26金沙注册送58 27

反射为大家付出提供了充裕便利的编制程序实践,但利用它也有几点要求小心。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Reflection;namespace ReflectionTestGet{    class Program    {        static void Main(string[] args)        {            Assembly asm = Assembly.LoadFrom("ClassLibrary.dll");  //加载指定的程序集            Type[] alltype = asm.GetTypes();  //获取程序集中的所有类型列表            foreach (Type calssName in alltype)            {                Console.WriteLine("加载程序的集类名:"+ calssName.Name);  //打印出程序集所有类                foreach (var field in calssName.GetFields                    Console.WriteLine(calssName.Name+"字段有:" + field.Name);  //打印出程序集所有字段,注意只能获取公有字段                foreach (var pro in calssName.GetProperties                    Console.WriteLine(calssName.Name + "属性有:" + pro.Name);  //打印出程序集所有属性                foreach (var met in calssName.GetMethods                    Console.WriteLine(calssName.Name + "方法有:" + met.Name);  //打印出程序集所有方法            }            Console.ReadKey();        }    }}

既然如此是反射,大家在编码时对品种是雾里看花的,倘使是已知,就没必要再用反射了,
除非是要做类似分析类型元数据的工具,而作者辈一般选取反射是要操作其属性字段、调用其艺术等,指标是用而不是分析。在编译使用了反光的代码进程中,反射的对象项目是不安全的,很有相当大希望在调用反射出来的类对象时出错,这点要留心。

View Code

反射是基于元数据达成的,所以在采纳反射进度中,代码会寻找程序集的元数据,那几个元数据是基于字符串的,并且不能预编写翻译,所以那1多级的操作对品质有生死攸关影响。此外,由于大家对目标项目未知,在向方法传递参数时平常是以object数组传递,CL福睿斯会各种检查参数的数据类型,无论是传入依然回到,都有非常大只怕展开大批量的类型转换,那也伤害了品质。所以对于反射的应用,应该小心。当然,像一些OOdysseyM等框架是以献身品质来换取方便的开发体验就另当别说了。

运维结果如下:

 

金沙注册送58 28

转自:

5.本节宗旨:

本节重点介绍和反光的用途及反光的宗旨操作类及质量方法,下节继续深切介绍如何将反射技术应用于实际项目里面。

==============================================================================================

回来目录

<倘若对你有赞助,记得点一下推荐哦,如有

**有不理解或不当之处,请多交流>**

<对本体系小说阅读有难堪的敌人,请先看《.net面向对象编制程序基础》>

<转发注明:技术供给共享精神,欢迎转发本博客中的作品,但请注脚版权及U卡宴L>

.NET
技术交换群:46718953三

金沙注册送58 29

==============================================================================================

相关文章

网站地图xml地图