【美高梅开户网址】行使反射将枚举绑定到下拉框,中的反射

序言:反射(Reflection)是.NET提供给开发者的二个强有力工具,固然作为.NET框架的使用者,很多时候不会用到反射。但在有个别地方下,尤其是在开发一些基础框架或公共类库时,使用反射会使系统架构越来越灵活。

引言

反射是.Net提必要大家的一件强力武器,就算超过一全场地下大家不常用到反射,就算我们可能也不供给掌握它,但对反射的应用作以伊始摸底在其后的付出中恐怕会具有帮衬。

反射是一个大幅的话题,牵扯到的知识点也很多,包涵程序集、自定义天性、泛型等,想要完全控制它可怜不错。本文仅仅对反射做3个马虎介绍,关于它越来越深邃的内容,必要在实践中慢慢控制。本文将分为下边多少个部分介绍.Net中的反射:

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

摘 要

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

 

序章

即便您还从未接触过反射,而本身以往就下一批定义告诉您怎么样是反光,相信您一定会有3头一棒的痛感。作者一贯认为那么些公理式的概念和定义唯有在你足够领悟的时候才能较好的发挥功效。所以,大家先来看三个开销中常蒙受的题材,再看看怎样行使反射来消除:

在展开数据库设计的历程中,平时会成立部分基础消息表,比如说:全国的都市,又或然订单的状态。若是我们将城市的表,起名称为City,它1般包涵类似那样的字段:

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

那个表将供广大别的表引用。要是大家在建立一个酒店预定系统,那么酒馆消息表(Hotel)就会引用此表,用CityId字段来引用酒馆所在城市。对于城市(City)表那种情景,表里存放的笔录(城市音信)是不定的,意思便是说:我们只怕随时会向这张表里添加新的城池(当有些城市的首先家旅馆想要参加预定系统时,就需求在City表里新添这家酒吧所在的都市)。此时,这样的统一筹划是说得有理的。

反射,一个很有用且有趣的风味。当动态创造某些项指标实例或是调用方法只怕访问对象成员时一般会用到它,它是依照程序集及元数据而工作的,所以那壹章我们来斟酌一下程序集、反射如何工作、怎么样动态创制类型及对象等休戚相关文化,甚至能够动态创设程序集。

本节导读:本节最首要介绍怎么样是.NET反射本性,.NET反射能为大家做些什么,最终介绍两种常用的反射的实现情势,通过对反射性特的领会,能够设计出至极实用的基于反射的编制程序情势。

在支付中,我们常常会际遇比如有些景况值在概念好后大概平昔不改动,那时候使用数据库就体现略微多余了。首先想到的2个方法只怕是在先后中创建三个数组来代表,此时,大家相见了采纳数组只怕带来的首先个难题:不方便使用。当数组结构改变时,可能代表全数应用过此数组的地点的目录都发出了改观,那是大家不想看看的。

一.建表及其难点

小编们再看看另外一种状态,大家必要标识饭馆预约的动静:未提交、已提交、已撤消、受理中、已退回、已订妥、已过期。此时,很多开发人士会在数据库中确立一张小表,叫做BookingStatus(预定景况),然后将如上意况进入进来,就如那样:

美高梅开户网址 1

就像是城市(City)表1样,在系统的任何表,比如说酒店订单表(HotelOrder)中,通过字段StatusId引用这么些表来获取旅馆预约景况。然则,多少个月未来,即使看起来和城市表的用法1样,结果却发现那个表只在数据库做一道查询可能只在程序中调用,却从不做修改,因为预定流程规定下来后壹般是不会改变的。在应用程序中,也不会给用户提供对这些表记录的增加和删除改操作界面。

而在程序中调用这一个表时,常常是那种意况:大家必要依照预定意况对订单列表进行筛选。此时常见的做法是接纳3个下拉菜单(DropDownList),菜单的数据源(DataSource),大家能够很自由地经过多个SqlDataReader得到,大家将DropDownList的文本Text设为Status字段,将值Value设为Id字段。

那会儿,我们理应已经发现标题:

  1. 要是大家还有航班预约、游船预约,或许其余1些景况,大家须要在数据库中开创很多看似的小表,造成数据库表的数据过多。
  2. 大家运用DropDownList等控件获取表内容时,须要三番五次到数据库进行询问,潜在地影响属性。

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

  1. 此表一般会在数据库联合查询中运用到。要是我们有表示客栈订单的HotelOrder表,它含有代表景况的StatusId字段,大家的查询恐怕会像这么:Select
    *, (Select Status From BookingStatus Where Id =
    HotelOrder.StatusId) as Status From HotelOrder。
  2. 在应用程序中,此表平常作为DropDownList恐怕其余List控件的数据源。
  3. 那么些表差不多从不改动。

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

读前少不了:

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

2.数组及其难题

发觉到这么设计存在难点,大家今后就想办法消除它。大家所想到的第四个办法是足以在程序中开创1个数组来表示预约景况,这样我们就足以删掉BookingStatus状态表(注意能够如此做是因为BookingStatus表的始末规定后大致向来不改动)。

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

大家先看它化解了哪些:下边提到的标题一、难点贰都化解了,既不须求在数据库中创造表,又无需一连到数据库实行询问。

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

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

最近甘休看上去还不易,以后大家要求进行三个操作,将订单的情景改为“受理中”。

myOrder.StatusId = 4;

很倒霉,大家发现了动用数组或许带来的率先个难点:不方便使用,当大家需求立异订单的情事值时,大家要求去查看BookingStatus数组的定义(除非您难忘全部意况的数字值),然后依照情状值在数组中的地点来给目的的本性赋值。

作者们再看另1个操作,假诺某些订单的气象为“已过期”,就要对它进行删除:

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

那时候的难点和地点的切近:大家需求手动输入字符串“已过期”,此时Vs2006的智能提示发挥不了任何意义,假诺大家不幸将气象值记错,只怕手误打错,就将导致程序错误,较为妥善的做法依旧按下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,也就是3个虚拟机(当然这么些虚拟机能够布置到自由援救它的系统环境中),在安装.NET
Framework时,CL帕杰罗的零件与别的COM一样在Windows系统中拥有同等的看待,当CLSportage运行先河化时会创制一个选拔程序域,应用程序域是一组先后集的逻辑容器,它会趁着进度的终止而被卸载销毁,CL中华V把程序代码所须求的次序集加载到当下(或钦点的)应用程序域内。CL卡宴能够以其伊始化时创立的使用程序域为根基再次创下设其他的新利用程序域,五个使用程序域中的代码不能够直接待上访问,当然可以因此“中介”举行数据传送。新的程序域创造完后CLRAV肆完全能够卸载它,以协同格局调用AppDomain.Unload方法即可,调用此办法后,CL酷路泽会挂起最近经过中的全部线程,接着查找并暂停止运输营在即将卸载的程序域内的线程,然后举行垃圾回收,最终主线程恢复运营。

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

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

3.枚举会同难题

只是不幸的事又发生了…
大家的预定程序分成两片段:壹部分为B/S端,在B/S端能够展开旅馆订单的
创造(未提交)、提交(已交由)、撤销提交(已裁撤),其它还是能够观看是否已订妥;1部分为C/S端,为酒馆的订座中央,它可以拓展别的景况的操作。

此时,对于一切系统的话,应该有一切的多少个情形。但对此B/S端来说,它只有未提交、已交给、已吊销、已订妥 多少个情景,对应的值分别为 一、二、叁、6。

大家回顾一下地点是什么样接纳数组来化解的,它存在2个弱点:我们私下认可地将订单状态值与数组的索引壹一对应地挂钩了起来。

所以在绑定DropDownList时,我们利用自增的法子来设定列表项的Value值;或许在展示状态时,大家因此lbStatus.Text
= BookingStatus[myOrder.StatusId];
这样的语句来形成。而当这种对应关系被打破时,使用数组的艺术就失效了,因为1旦不行使数组索引,大家向来不额外的地方去存款和储蓄状态的数字值。

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

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

大家想在页面输出四个订单的境况时,能够如此:

HotelOrder myOrder = GetItem(orderId);         //获取八个订单对象
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类型,那样操作会越发便捷壹些,但为了和前边使用数组时的情事保持统壹,那里StatusId仍利用int类型。

以上二种情景使用枚举都显得特其余流畅,直到大家供给绑定枚举到DropDownList下拉列表的时候:大家通晓,能够绑定到下拉列表的有两类对象,1类是落实了IEnumerable接口的可枚举集合,比如ArrayList,String[],List<T>;一类是贯彻了IListSource的数据源,比如DataTable,DataSet。

NOTE:实际上IListSource接口的GetList()方法重回3个IList接口,IList接口又一而再了IEnumerable接口。因此看来,IEnumerable是落实可枚举集合的根基,在本人翻译的一篇文章
C#中的枚举器
中,对这么些主题做了详实的座谈。

可大家都知情:枚举enum是贰个基本类型,它不会兑现任何的接口,那么大家下来该如何做吧?

【美高梅开户网址】行使反射将枚举绑定到下拉框,中的反射。其余Windows程序都得以寄宿CL中华V,1台机上能够安装几个版本的CLCR-V。Windows在开发银行叁个托管的顺序时会先运行MSCorEE.dll中的1个艺术,该措施在在那之中依据2个托管的可执行文件消息来加载相应版本的CL兰德酷路泽,CLOdyssey起初实现现在,将次第集加载到使用程序域,最终CLGL450检查程序集的CLXC60头音信找到Main方法并推行它。

1.什么是.NET反射?

在实际上利用中,可能必要用户下拉摘取那一个景况值,那时就须要咱们把枚举绑定到下拉框上(此处以Combobox为例)了。我们领悟,能够绑定到下拉框列表的有两类别型:1种是贯彻了IEnumerable接口的可枚举类型,比如ArrayList,String[],List<T>;壹类是贯彻了IListSource的数据源,比如DataTable,DataSet。

4.应用反射遍历枚举字段

最笨也是最不难易行的措施,我们得以先创设3个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;
 }

接下去,为了方便使用,大家再成立3个特意使用那么些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出3个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个是字段的公文(比如“未提交”),二个是字段的数字型值(比如1),我们暂时管这些目的叫做田野。其次,应该存在一个可遍历的、包罗了字段新闻的对象(约等于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类,以往只期待你能对反射有个第2影像,所以只简不难单地作以表达:Type抽象类提供了拜访类型元数据的能力,当你实例化了多个Type对象后,你可以经过它的个性和方法,获取项目标元数据音讯,大概进一步赢得该品种的积极分子的元数据。小心到此处,因为Type对象总是基于某1门类的,并且它是1个抽象类,之所以大家在创设Type类型时,要求求提供
类型,或然项指标实例,或许项目标字符串值(Part.2会表明)。

创制Type对象有很各样措施,本例中,大家运用typeof操作符来展开,并传递BookingStatus枚举:

Type enumType = typeof(BookingStatus);

然后,大家理应想方法获得 封装了字段新闻的对象 的成团。Type类提供
GetFields()方法来促成那1进度,它回到1个 FieldInfo[]
数组。实际上,也正是上边大家enumFields集合的类型。

FieldInfo[] enumFields = enumType.GetFields();

明日,大家就足以遍历这一汇合:

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

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

大家看一看完整的代码:

private static DataTable GetDataTable() {

     Type enumType = typeof(BookingStatus);    // 创立项目
     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;
 }

在意,SetListControl()方法依然留存并有效,只是为了节省篇幅,作者尚未复制过来,它的运用和以前是同样的,大家只是修改了GetDataTable()方法。

 

反射是.NET一个人命关天的性情,《CLEnclaveviaC#》一书中对.NET反射的分解为:在我们应用程序中采用元数据来表示存款和储蓄。编写翻译程序集或模块时,编写翻译器会创立一个系列定义表、一个字段定义表、贰个主意定义表以及其它表。而我们只要想动态调用那么些元数据表,或视为为这几个元数据创立多少个对象模型,那些历程便是反光。

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

5.选用泛型来完结代码重用

考查地点的代码,尽管大家前几天有另多个枚举,叫做TicketStatus,那么大家要将它绑定到列表,大家唯1须求改变的便是此处:

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#
中的泛型
一文。下边包车型客车实现并未设想到品质的标题,仅仅为了引出反射使用的三个实例。

第2节 加载程序集

粗略易懂的说,便是动态调用编写翻译过的程序集中的质量,字段,方法等的进程,就是反光。

 

6 .Net 中反射的一个范例。

不管是VS2005的智能提示,照旧修改变量名时的重构功效,都采取了反光作用。在.Net
FCL中,也常常能看出反射的黑影,那里就向我们演示一个最广泛的事例。大家清楚,在CL福特Explorer中壹共有二种档次,一种是值类型,1种是引用类型。声Bellamy个引用类型的变量并对品种实例化,会在应用程序堆(Application
Heap)上分配内部存款和储蓄器,创制对象实例,然后将对象实例的内部存款和储蓄器地址再次回到给变量,变量保存的是内存地址,实际也正是贰个指针;声宾博(Karicare)个值类型的实例变量,则会将它分配在线程堆栈(Thread
Stack)上,变量本人包蕴了值类型的有所字段。

前天若是我们需求比较多个目的是或不是等于。当我们比较三个引用类型的变量是还是不是等于时,大家比较的是那四个变量所指向的是否堆上的同1个实例(内存地址是或不是一律)。而当大家相比较五个值类型变量是或不是等于时,怎么办吗?因为变量自己就包括了值类型全部的字段(数据),所以在比较时,就须要对三个变量的字段举办逐项的万分的可比,看看每种字段的值是或不是都分外,就算别的3个字段的值不等,就回到false。

实质上,执行那样的3个比较并不必要大家协调编排代码,Microsoft已经为大家提供了完毕的格局:全体的值类型继承自
System.ValueType, ValueType和拥有的连串都三番八回自System.Object
,Object提供了2个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()方法开发是会十分大的。可是这几个事例只是为了印证反射的用途,笔者想已经达到规定的标准了目标。上面的代码不能够一心精通也没什么,前边会再涉及。

程序集是有所品类的聚众,它还有三个至关心注重要的事物便是元数据。JIT正是选用程序集的TypeRef和AssemblyRef等元数据来规定所引用的先后集及项目,那么些元数据包涵名称、版本、语言文化和公钥标记等,JIT正是依据那些音讯来加载1个顺序集到应用程序域中。假如要团结加载1个程序集,能够调用类型Assembly的LoadXXX连串措施。

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

应用反射遍历枚举字段

7.小结

观察那里,你应该对反射有了三个开端的概念(也许叫反射的二个用场):反射是壹种普遍的叫法,它通过
System.Reflection 命名空间 并 协作 System.Type
类,提供了在运转时(Runtime)对于 类型和对象(及其成员)的骨干消息 以及
元数据(metadata)的拜会能力。

 

(1) Load重载系列

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

要遍历枚举,首先就供给2个富含枚举每一个字段音信的目的,那么些目的至少应该包涵四个天性,二个是字段的称号,3个是字段的值,以有益后续绑定。

该方法会依照一定的逐条查找钦定目录中的程序集:先去GAC中追寻(就算是1个强命名程序集),假诺找不到,则去应用程序的基目录、子目录查找。倘诺都没找到,则抛出尤其。如下代码加载程序集MyAssemblyB:

以此标题是我们上学反射的第1,总得知道学习它的好处,才会继续把本文看下来。

先看下完整的代码:

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

反射天性,确实是.NET1个可怜重大且使得的特征。

        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.实例化新指标

效果:美高梅开户网址 2

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

C.执行对象成员

此地质大学致做2个验证:Type抽象类提供了走访类型元数据的力量,当实例化了三个Type对象后,能够透过它的品质和方法,获取项指标元数据的讯息,只怕进一步获得该品种的积极分子的元数据信息。注意到那边,因为Type对象总是基于某一有血有肉项指标,并且它是三个抽象类,所以再成立Type类型时,需求提供项目名称只怕项目的实例。程序集元数据,通过Type类型就足以访问类型的元数据音信,而访问类型元数据的操作,就叫做反射。

(3) LoadFile重载类别

D.查找类型新闻

 

从随机路径加载三个程序集,并且可以从不一致途径加载相同名称的主次集。

E.查询程序集音信

选拔泛型来达成代码重用

在二个档次中,大概程序集以内都有依靠关系,也足以将2个程序集作为财富数量嵌入到二个顺序集中,在要求时再加载该程序集,那时通过注册ResolveAssembly事件来加载那几个顺序集。如下;

F.检查选择于某种类型的自定义本性

调查地点的代码,若是明天有另八个枚举,叫做TicketStatus,那么要将它的枚举项文件和值转换为DataTable,唯壹需求改变的正是此处:

美高梅开户网址 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的不2法门更改为泛型方法:

美高梅开户网址 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)

下边列举三种基于反射设计情势下的实例:

借使准备调用上边那八个形式加载的次序集中类型的代码,则CLLacrosse会抛出相当。

A.利用反射创动态创制造进程序集的API文书档案。基于反射允许枚举程序集中类型及成员的特点,大家得以由此反射获取已编写翻译的次第集中的字段方法属性事件和她俩的XML注释。从而动态创设程序集的API文档;

 

B.非日常用的反光工厂格局。反射工厂方式在设计格局中比较易于精通,也相比较简单。很多代码生成器中就应用那种设计情势达成分裂数据库的反射调用。比如大家有MsSql、MySql、Oracle那两种数据库,在项目规划中,我们有不小可能率随时换另1种数据库,因而需求同时落实这三种数据库的底子增加和删除改查的类即数据访问类。大家要切换数据库的时候,只供给在config中改变数据库类型,其余的行事交给反射工厂类去动态调用编写翻译好的顺序集中对应的数据库访问方法。

第三节 反射

假如未有通晓也没提到,那里只是说澳优下反光的利用实例,以便于更有信念的求学反射。反射在设计情势中的应还有许多,那里不再列举。

我们领悟,在程序集(或模块)内有一个很关键的数据便是元数据,它们描述了花色定义表,字段定义表,方法表等,相当于说全体的品类及成员定义项都会在此地被了然详细地记录下来。很鲜明,即使大家获得了这么些“描述音讯”,当然就也就是已老板解知晓了一个类型及其成员,进而就能够“构造”这一个项目,通过反射就足以达到规定的标准如此的指标。另人欢畅的是大家不用分析那三个元数据就足以便宜地得到程序集内的品类成员,.NET
Framework提供了部分与此相关的类定义在命名空间System.Reflection下。

叁.反光应用基础

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

地点说了如此多,无非正是先让我们掌握反射能为我们做些什么,上面进入正题,说一下反光的代码落成。

(一)查找程序集内所定义的门类

上边主要介绍反射的大旨类及类成员

在将某一程序集加载到使用程序域后,能够透过Assembly的GetExportedTypes方法来取得该程序集全部的当众类型,如下代码:

反射的命名空间:System.Reflection

美高梅开户网址 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

美高梅开户网址 6

那一个类是反射的宗旨,其性子方法可以获取周转时的新闻。

(2)查找类型成员

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

在命名空间System.Reflection中有1个虚无类型MemberInfo,它包裹了与品种成员相关的通用属性,每1个体系成员都有一个对应的从MemberInfo派生而来的花色,并且放置了有个别特殊的性格特征,如菲尔德Info、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 //获取属性

备注

同时各个方法都能够收起二个枚举类型BindingFlags的参数钦点控制绑定和由反射执行的分子和体系搜索方法的申明。有关BindingFlags
枚举可参看MSDN文档.aspx%E3%80%82)

TypeDeclaringType

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

收获注明该成员的类或接口的项目

美高梅开户网址 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");
        }

获得成员的档次,那个值用于提醒该成员是字段、方法、属性、事件、或构造函数

美高梅开户网址 8

这是多少个枚举,它定义了用于表示差别成员的类型值。这个值包含:MemberTypes.Constructor,MemberTypes.Method,MemberTypes.菲尔德,MemberTypes.伊芙nt,MemberTypes.Property。因而能够透过检查MemberType属性来规定成员的档次,例如,在MemberType属性的值为MemberTypes.Method时,该成员为艺术

(叁)构造类型实例

IntMetadataToken

在得到项目及成员音信之后,大家就足以构造类型的实例对象了。FCL提供了多少个方式来组织1个连串的实例对象,有关这么些办法详细内容,可参照MSDN文书档案:

取得与特定元数据有关的值

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

ModuleModule

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

收获二个意味反射类型所在模块的Module对象

美高梅开户网址 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);
        }

分子的名号

美高梅开户网址 10

TypeReflectedType

看一下调剂:

反射的靶子类型

美高梅开户网址 11

Type类的只读属性

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

属性

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

描述

 

AssemblyAssembly

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

获得钦点项指标程序集

只要1味收获类型的靶子,好像意义并非常的小,大家越多的是要操作对象,比如访问属性,调用方法等,那一节我们来看一下怎样访问成员。

TypeAttributesAttributes

品种Type提供了多个做客目的项目成员的不行可相信的艺术InvokeMember,调用此格局时,它会在类型成员中找到对象成员(那平常钦命成员名称,也得以钦定搜索筛选标准BindingFlags,假使调用的靶子成员是格局,还足以给艺术传递参数。),假若找到则调用目的措施,并赶回指标访问回到的结果,要是未找到,则抛出尤其,假设是在对象措施内部有那叁个,则InvokeMember会先捕获该特别,包装后再抛出新的百般TargetInvocationException。以下是InvokeMember方法的原型:

取得制定项目标特色

美高梅开户网址 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 传递给目标方法的参数

得到内定项指标第一手基类型

美高梅开户网址 13

美高梅开户网址 ,StringFullName

在上①节的结尾大家来得了什么调用类型的构造函数来实例化三个目的,上面包车型地铁代码演示了如何调用对象的措施,在那之中措施Turn接收贰个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类的不二等秘书籍

以上的示范都以指向普通品种,其实反射也提供了对泛型的支撑,那里只不难演示一下反光对泛型的简要操作。比如大家有如下2个泛型类型定义:

方法

美高梅开户网址 14

描述

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

ConstructorInfo[]GetConstructors()

美高梅开户网址 15

收获内定项目标构造函数列表

其1连串很简单,类型MyGeneric内有三个艺术,该措施再次回到带有附加消息”
Generic Name:”的称谓。先来看一下怎么着取得钦点参数类型为string的泛型类:

EventInfo[]GetEvents();

美高梅开户网址 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();

美高梅开户网址 17

收获钦命项指标字段列

调节起来,看一下最终的value值:

Type[]GetGenericArguments();

美高梅开户网址 18

收获与已布局的泛型类型绑定的类型参数列表,若是内定项目标泛型类型定义,则得到类型形参。对张晓芸早布局的项目,该列表就大概同时涵盖类型实参和类型形

反射泛型的时候,要先分明目的项目是泛型,在创造泛型类型实例前,必须调用MakeGenericType方法组织2个的确的泛型,该格局接收3个要钦点泛型类型参数的项目数组,同样调用泛型方法前要调用方法MakeGenericMethod构造相应的泛型方法,此办法也收到三个点名泛型类型的档次数组。

MethodInfo[]GetMethods();

 

收获钦赐项指标格局列表

第伍节 动态创立类型

PropertyInfo[]GetProperties();

日前几节所讲述的都以基于已经存在程序集的图景下展开反射,.NET
Framework还提供了在内部存款和储蓄器中动态创制类型的有力成效。大家领略程序集包涵模块,模块包蕴项目,类型包罗成员,在动态成立类型的时候也是要绳趋尺步那些顺序。动态创设类型是基于元数据的完结方式来兑现的,那一有些被定义在命名空间System.Reflection.Emit内,有一名目繁多的XXXBuilder构造器来创立相应的品类对象。大家来看一要动态创设类型,有啥样步骤(那里只是简单演示):

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

(1) 程序集是老窝,所以要先创制三个程序集:

MemberInfo[]GetMembers();

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

获取钦赐项指标积极分子列表

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

反射还有很多类,那里不一一介绍,详细能够查阅MSDN:

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

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

4.反射实例

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

上面通过三个实例来学习一下反光最中央的运用办法。

(四)
未来能够创设项指标成员了,为品种创造1脾品质Name。大家理解属性包括字段和对字段的三个访问器,所以理应先创制字段,然后再次创下制四个访问器方法,那壹段是遵循IL码的先后顺序来的,如下:

树立二个缓解方案,包罗七个品类,项目ClassLibrary生成三个DLL,另一个类型是ReflectionTestGet,用于反射调用类ClassLibrary

美高梅开户网址 19

美高梅开户网址 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);

第3个品种的七个类如下:

美高梅开户网址 21

MartialArtsMaster.cs

留意,那里面有对事件的操作,可以忽略。

美高梅开户网址 22美高梅开户网址 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

该格局重返八个Type类型。

Person.cs

品种创立实现后,我们就能够动用上1节讲的反光相关文化对该类型举办操作了,那里当然是2个粗略的体系,如若想创建复杂的系列,比如有方法,事件等成员,那能够表达您的汇编能力来渐渐折腾呢,也得以回味一下当即汇编制程序序员们的苦逼!托管下的汇编编码已经很简化了,围绕Emit方法折腾死!如若想商量IL,能够用IL
DASM打开托管程序集,逐步欣赏吧。

美高梅开户网址 24美高梅开户网址 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

 

第二个品类调用如下:

第5节 应用反射时要注意的几点

美高梅开户网址 26美高梅开户网址 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

反射是基于元数据完结的,所以在利用反射进程中,代码会寻找程序集的元数据,那些元数据是按照字符串的,并且不可能预编写翻译,所以这一名目繁多的操作对品质有生死攸关影响。其余,由于大家对指标项目未知,在向方法传递参数时常常是以object数组传递,CL汉兰达会每一种检查参数的数据类型,无论是传入照旧回到,都有希望开始展览大气的类型转换,那也加害了品质。所以对于反射的选择,应该注意。当然,像有个别OMuranoM等框架是以捐躯质量来换取方便的费用体验就另当别说了。

运作结果如下:

 

美高梅开户网址 28

转自:

5.本节中央:

本节根本介绍和反光的用途及反光的骨干操作类及品质方法,下节后续深入介绍怎么着将反射技术使用于实际项目里面。

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

回到目录

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

**有不晓得或不当之处,请多交流>**

<对本类别作品阅读有困难的朋友,请先看《.net面向对象编制程序基础》>

<转载注脚:技术供给共享精神,欢迎转发本博客中的小说,但请注明版权及ULacrosseL>

.NET
技术交流群:46718953三

美高梅开户网址 29

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图