中的反射,获取音信详细

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

引言

反射是.Net提须要大家的一件强力武器,尽管超过四分之2气象下大家不常用到反射,固然大家只怕也不须要精通它,但对反射的使用作以起初摸底在未来的费用中大概聚会场全数帮忙。

反射是二个庞然大物的话题,牵扯到的知识点也很多,包蕴程序集、自定义性情、泛型等,想要完全控制它充足不利。本文仅仅对反射做贰个概况介绍,关于它更加高深的剧情,供给在实践中逐步控制。本文将分成上边多少个部分介绍.Net中的反射:

  1. 序章,作者将透过叁个例子来引出反射,获得对反射的第二影像。
  2. 反射初始、Type类、反射普通品种。(修改中,近日发布…)
  3. 反射性情(Attribute)。
  4. xxxx (待定)

摘 要

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

 

序章

若果您还从未接触过反射,而自小编今后就下一批定义告诉您怎么是反光,相信您一定会有三只壹棒的感觉。我一直以为那几个公理式的概念和定义只有在你就算领略的时候才能较好的发挥效能。所以,大家先来看七个开销中常境遇的题目,再看看哪些利用反射来缓解:

在开始展览数据库设计的经过中,日常会树立部分基础消息表,比如说:全国的城池,又只怕订单的景况。假使大家将城市的表,起名称叫City,它平日包括类似那样的字段:

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

以此表将供广大任何表引用。借使大家在确立二个饭店预定系统,那么饭馆新闻表(Hotel)就会引用此表,用CityId字段来引用酒店所在城市。对于城市(City)表那种景色,表里存放的笔录(城市消息)是不定的,意思正是说:我们大概每一日会向这张表里添加新的都会(当有些城市的首先家酒吧想要参加预定系统时,就须求在City表里新添这家酒吧所在的城市)。此时,那样的布置性是入情入理的。

反射,一个很有用且妙趣横生的特征。当动态创造有些项目标实例或是调用方法可能访问对象成员时平日会用到它,它是依照程序集及元数据而工作的,所以那一章大家来探究一下程序集、反射怎样工作、怎么着动态创立类型及对象等连锁文化,甚至足以动态创制造进程序集。

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

在开发中,大家通常会遇上比如有个别情状值在概念好后大概一直不改动,那时候使用数据库就突显略微多余了。首先想到的几个艺术或者是在程序中制造一个数组来代表,此时,大家相遇了选拔数组恐怕带来的率先个难题:不方便使用。当数组结构改变时,只怕代表全部应用过此数组的地方的目录都产生了转移,那是我们不想看到的。

①.建表及其难点

笔者们再看看此外一种情景,大家须要标识旅社预约的景色:未提交、已交付、已撤销、受理中、已退回、已订妥、已过期。此时,很多开发人士会在数据库中确立一张小表,叫做BookingStatus(预订意况),然后将如上情形投入进去,就恍如那样:

亚洲必赢官网 1

犹如城市(City)表1样,在系统的别的表,比如说旅社订单表(HotelOrder)中,通过字段StatusId引用那一个表来获取旅舍预约景况。不过,多少个月之后,固然看上去和都市表的用法壹样,结果却发现这一个表只在数据库做联合查询或许只在程序中调用,却不曾做修改,因为预定流程规定下来后一般是不会变动的。在应用程序中,也不会给用户提供对那一个表记录的增加和删除改操作界面。

而在程序中调用那几个表时,平日是那种景观:大家需求依照预定情形对订单列表举行筛选。此时常见的做法是应用2个下拉菜单(DropDownList),菜单的数据源(DataSource),大家得以很轻易地经过1个SqlData里德r得到,大家将DropDownList的文本Text设为Status字段,将值Value设为Id字段。

这时候,大家应该已经发现标题:

  1. 假设我们还有航班预约、游船预约,大概别的1些情景,我们必要在数据库中开创很多接近的小表,造成数据库表的数额过多。
  2. 作者们利用DropDownList等控件获取表内容时,须求一连到数据库举行询问,潜在地影响属性。

并且,大家也留意到三点:

  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从一开始。

大家先看它消除了何等:上面提到的题材一、难点2都化解了,既不必要在数据库中创立表,又无需一连到数据库实行查询。

大家再看看当大家想要用文件展现宾馆的预定时,该怎么办(假如有订单类HotelOrder,其质量StatusId代表订单状态,为int类型
)。

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

近来截止看上去基本上能用,未来我们供给开始展览三个操作,将订单的景况改为“受理中”。

myOrder.StatusId = 4;

很沮丧,我们发现了接纳数组也许带来的率先个难点:不方便使用,当大家必要更新订单的图景值时,大家需求去查看BookingStatus数组的定义(除非你难以忘怀所有情形的数字值),然后根据事态值在数组中的地点来给指标的性质赋值。

大家再看另2个操作,假若有个别订单的地方为“已过期”,就要对它实行删除:

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

此刻的题材和方面包车型大巴近乎:我们须求手动输入字符串“已过期”,此时Vs二〇〇六的智能提示发挥不了任何成效,假诺大家不幸将处境值记错,或许手误打错,就将招致程序错误,较为安妥的做法依旧按下F12导向到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奥迪Q5其实就是COM,约等于三个虚拟机(当然那个虚拟机能够布置到自由帮助它的系统环境中),在安装.NET
Framework时,CLHighlander的零件与别的COM1样在Windows系统中具备同等的待遇,当CLLX570运转最先化时会创制多少个利用程序域,应用程序域是1组先后集的逻辑容器,它会趁机进度的告壹段落而被卸载销毁,CLCR-V把程序代码所急需的程序集加载到当前(或钦定的)应用程序域内。CLENVISION能够以其发轫化时创建的使用程序域为底蕴再次创下造别的的新利用程序域,七个使用程序域中的代码不能够一向访问,当然能够通过“中介”进行数量传送。新的程序域制造完后CL哈弗完全能够卸载它,以联合格局调用AppDomain.Unload方法即可,调用此办法后,CLOdyssey会挂起近年来经过中的全体线程,接着查找并暂停止运输营在快要卸载的程序域内的线程,然后开始展览垃圾回收,最后主线程复苏运维。

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

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

三.枚举及其难点

而是不幸的事又发出了…
大家的预购程序分成两局地:1部分为B/S端,在B/S端能够进行酒馆订单的
创造(未提交)、提交(已交付)、打消提交(已吊销),其它还是能看来是或不是已订妥;一部分为C/S端,为饭店的预约大旨,它能够举办别的意况的操作。

那儿,对于整个系统来说,应该有总体的四个情景。但对于B/S端来说,它只有未提交、已交付、已撤除、已订妥 多个情景,对应的值分别为 一、二、三、陆。

大家回想一下地点是什么使用数组来消除的,它存在2个弱点:我们暗中认可地将订单状态值与数组的索引壹一对应地挂钩了肆起。

故此在绑定DropDownList时,大家应用自增的主意来设定列表项的Value值;可能在突显状态时,大家经过lbStatus.Text
= BookingStatus[myOrder.StatusId];
那样的语句来形成。而当那种对应关系被打破时,使用数组的法子就失效了,因为固然不行使数组索引,大家从不额外的地点去存款和储蓄状态的数字值。

亚洲必赢官网 ,此刻,大家想到了动用枚举:

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 2005的智能提示已经足以表达完全意义,当我们在BookingStatus后按下“.”时,能够展现出装有的意况值。

NOTE:当大家使用枚举存款和储蓄状态时,myOrder对象的StatusId最棒为BookingStatus枚举类型,而非int类型,那样操作会越发方便人民群众壹些,但为了和日前使用数组时的情形保持统一,那里StatusId仍利用int类型。

上述二种情状使用枚举都显得卓殊的流利,直到大家必要绑定枚举到DropDownList下拉列表的时候:我们领略,能够绑定到下拉列表的有两类对象,一类是促成了IEnumerable接口的可枚举集合,比如ArrayList,String[],List<T>;1类是促成了IListSource的数据源,比如DataTable,DataSet。

NOTE:实际上IListSource接口的GetList()方法再次来到3个IList接口,IList接口又继续了IEnumerable接口。因而看来,IEnumerable是完结可枚举集合的根基,在自家翻译的一篇小说
C#中的枚举器
中,对这些主旨做了详实的座谈。

可大家都精晓:枚举enum是一个主干类型,它不会完毕其余的接口,那么大家下来该怎么做吧?

任何Windows程序都足以寄宿CLLAND,壹台机上能够安装三个本子的CL奥迪Q5。Windows在开发银行八个托管的先后时会先运行MSCorEE.dll中的二个形式,该形式在其间依据3个托管的可执行文件音信来加载相应版本的CLPAJERO,CLLX570初叶达成之后,将顺序集加载到应用程序域,最终CLTiguan检查程序集的CL帕杰罗头音信找到Main方法并执行它。

1.什么是.NET反射?

在骨子里运用中,恐怕须求用户下拉挑选那个情状值,那时就要求我们把枚举绑定到下拉框上(此处以Combobox为例)了。我们精晓,能够绑定到下拉框列表的有两系列型:1种是落到实处了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);

本条时候,大家想有未有方法通过遍历来促成那里?假诺想要遍历那里,首先,大家必要二个分包枚举的各个字段音信的靶子,那几个目的至少含有两条音信,三个是字段的文件(比如“未提交”),贰个是字段的数字型值(比如一),我们一时管那一个指标叫做田野(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)的对象的品种。而对此enum菲尔德s,它的花色应该是xxxx那一个类型的成团。那段代码是大家根据思路假想和演绎出来的。实际上,.Net
中提供了 Type类 和 System.Reflection命名空间来提携缓解大家今日的难点。

自己在末端将较详细地介绍
Type类,未来只盼望你能对反射有个第一印象,所以只简容易单地作以表达:Type抽象类提供了走访类型元数据的能力,当你实例化了1个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类型的值。

大家看一看完整的代码:

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二个至关心重视要的表征,《CLHavalviaC#》1书中对.NET反射的诠释为:在我们应用程序中使用元数据来表示存款和储蓄。编写翻译程序集或模块时,编写翻译器会创建二个品类定义表、三个字段定义表、三个方式定义表以及任何表。而小编辈只要想动态调用那几个元数据表,或视为为那个元数据成立贰个指标模型,这些进度正是反射。

可是,枚举enum是3个中坚项目,它不会促成任何的接口,显明,不能直接将枚举绑定到下拉框上,那么相应利用什么艺术吧?

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#
中的泛型
一文。上边的落到实处并未设想到品质的题材,仅仅为了引出反射使用的一个实例。

其次节 加载程序集

简单来讲通俗的说,正是动态调用编写翻译过的次第集中的质量,字段,方法等的进度,正是反射。

 

陆 .Net 中反射的3个范例。

不论是VS2005的智能提示,照旧修改变量名时的重构作用,都应用了反光功效。在.Net
FCL中,也时不时能来看反射的影子,那里就向大家演示1个最普遍的例子。大家精晓,在CL本田UR-V香港中华总商会计有二种档次,一种是值类型,一种是引用类型。声澳优个引用类型的变量并对项目实例化,会在应用程序堆(Application
Heap)上分配内存,创设对象实例,然后将目的实例的内存地址重临给变量,变量保存的是内部存款和储蓄器地址,实际相当于2个指南针;声爱他美个值类型的实例变量,则会将它分配在线程堆栈(Thread
Stack)上,变量自身含有了值类型的持有字段。

明日假如大家必要相比三个目标是不是等于。当大家比较七个引用类型的变量是不是等于时,我们比较的是那七个变量所针对的是还是不是堆上的同一个实例(内部存款和储蓄器地址是还是不是一致)。而当大家比较四个值类型变量是不是等于时,怎么办吗?因为变量本身就带有了值类型所有的字段(数据),所以在相比时,就要求对五个变量的字段举行逐项的一定的比较,看看每一种字段的值是还是不是都等于,假诺其余3个字段的值不等,就回来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()方法时会产生怎么样事吗?后面大家曾经关系假如是值类型,会对三个变量的字段举行每一种的相比较,看看每种字段的值是不是都等于,不过怎么样取得变量的拥有字段,遍历字段,并逐1相比较呢?此时,你应当发现到又到了用到反射的时候了,让我们接纳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就是依据那一个音信来加载3个顺序集到利用程序域中。假诺要团结加载一个程序集,能够调用类型Assembly的LoadXXX连串措施。

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

利用反射遍历枚举字段

7.小结

看到此间,你应有对反射有了1个方始的定义(可能叫反射的3个用途):反射是壹种常见的叫法,它经过
System.Reflection 命名空间 并 合作 System.Type
类,提供了在运行时(Runtime)对于 类型和指标(及其成员)的主干音信 以及
元数据(metadata)的走访能力。

 

(一) Load重载种类

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

要遍历枚举,首先就供给3个饱含枚举种种字段消息的靶子,这些目的至少应当包括八个特性,多个是字段的称呼,三个是字段的值,以利于后续绑定。

该方法会依据一定的逐1查找钦定目录中的程序集:先去GAC中找寻(假使是2个强命名程序集),假如找不到,则去应用程序的基目录、子目录查找。如若都没找到,则抛出卓殊。如下代码加载程序集MyAssemblyB:

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

先看下完整的代码:

            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方法,并且还能钦命1个网络路径,假使钦定网络路径,则先下载该程序集,再将其加载到程序域,如下代码:

B.实例化新目的

效果:亚洲必赢官网 2

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

C.执行对象成员

那边大概做3个证实:Type抽象类提供了走访类型元数据的能力,当实例化了贰个Type对象后,能够因此它的质量和章程,获取项目标元数据的音讯,大概进一步取得该类型的分子的元数据消息。注意到此地,因为Type对象总是基于某一切实可行品种的,并且它是三个抽象类,所以再次创下制Type类型时,须要提供项目名称可能项目标实例。程序集元数据,通过Type类型就能够访问类型的元数据信息,而访问类型元数据的操作,就叫做反射。

(三) LoadFile重载种类

D.查找类型音讯

 

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

E.查询程序集新闻

动用泛型来达到代码重用

在一个品类中,恐怕程序集以内都有依靠关系,也能够将贰个程序集作为能源数量嵌入到贰个顺序集中,在急需时再加载该程序集,那时通过注册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#4.0随后新功能)

既是那样,就足以行使泛型来落实代码的录用,将赶回DataTable的法门更改为泛型方法:

亚洲必赢官网 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#高档编制程序》

从上述代码能够看出,综合运用反射,泛型等技巧,能够非常大地升高代码的油滑,可重用性。

如果只是想询问三个主次集的元数据解析其连串而不调用类型的成员,为了抓牢性能,能够调用那几个措施:

依照上边的中坚性子,大家可以安插出无数十三分实用的编制程序情势。

 

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

上边列举两种基于反射设计方式下的实例:

假使打算调用下面那四个章程加载的主次集中类型的代码,则CL中华V会抛出相当。

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

 

B.非平时用的反光工厂形式。反射工厂情势在设计形式中相比较易于理解,也相比较不难。很多代码生成器中就应用那种设计方式完毕差别数据库的反射调用。比如大家有MsSql、MySql、Oracle那二种数据库,在项目统筹中,大家有望随时换另一种数据库,因而须要同时落到实处那三种数据库的基础增加和删除改查的类即数据访问类。大家要切换数据库的时候,只必要在config中改变数据库类型,其余的行事交给反射工厂类去动态调用编写翻译好的顺序集中对应的数据库访问方法。

第三节 反射

借使未有驾驭也没提到,那里只是说Bellamy(Bellamy)下反光的使用实例,以便于更有信念的读书反射。反射在设计情势中的应还有众多,那里不再列举。

大家精晓,在程序集(或模块)内有一个很重点的多少正是元数据,它们描述了项目定义表,字段定义表,方法表等,也正是说全部的类型及成员定义项都会在那边被领悟详细地记录下来。很扎眼,倘若大家得到了那个“描述消息”,当然就一定于已经明白知晓了2个门类及其成员,进而就能够“构造”那么些连串,通过反射就能够达到规定的标准那样的指标。另人雅观的是我们不用分析那多少个元数据就能够方便地取得程序集内的门类成员,.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中有2个华而不实类型MemberInfo,它包裹了与项目成员相关的通用属性,每三个档次成员都有3个相应的从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有1组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

那是3个枚举,它定义了用来表示区别成员的类型值。这个值包蕴:MemberTypes.Constructor,MemberTypes.Method,MemberTypes.Field,MemberTypes.伊夫nt,MemberTypes.Property。由此得以经过检查MemberType属性来规定成员的花色,例如,在MemberType属性的值为MemberTypes.Method时,该成员为情势

(3)构造类型实例

IntMetadataToken

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

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

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

ModuleModule

1般来说构造奥迪(Audi)Car类型的实例:

取得2个代表反射类型所在模块的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提供了2个造访指标项目成员的十一分可靠的章程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类的方法

以上的以身作则都以对准普通品种,其实反射也提供了对泛型的支撑,那里只简简单单演示一下反光对泛型的大约操作。比如大家有如下一个泛型类型定义:

方法

亚洲必赢官网 14

描述

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

ConstructorInfo[]GetConstructors()

亚洲必赢官网 15

赢得钦点项指标构造函数列表

本条类型很粗大略,类型MyGeneric内有1个主意,该办法再次来到带有附加消息”
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个着实的泛型,该措施接收三个要钦点泛型类型参数的档次数组,同样调用泛型方法前要调用方法MakeGenericMethod构造相应的泛型方法,此办法也吸收3个点名泛型类型的品类数组。

MethodInfo[]GetMethods();

 

取得钦命项指标主意列表

第4节 动态创设类型

PropertyInfo[]GetProperties();

眼前几节所描述的都以依照已经存在程序集的景象下进行反射,.NET
Framework还提供了在内部存款和储蓄器中动态创制类型的雄强功效。我们领会程序集包罗模块,模块包蕴项目,类型包罗成员,在动态成立类型的时候也是要循途守辙那些顺序。动态创制类型是遵照元数据的兑现情势来兑现的,这一某个被定义在命名空间System.Reflection.Emit内,有一层层的XXXBuilder构造器来成立相应的品种对象。大家来看一要动态成立类型,有啥样步骤(那里只是不难演示):

取得内定项指标属性列表e

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

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);

下边通过一个实例来上学一下反光最中央的采纳方法。

(四)
以往能够创制项目标积极分子了,为品种创制2本个性Name。我们知道属性包括字段和对字段的多个访问器,所以应超过创建字段,然后再次创下制四个访问器方法,那1段是依据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);

第四个品种的五个类如下:

亚洲必赢官网 21

MartialArtsMaster.cs

留意,那中间有对事件的操作,能够忽略。

亚洲必赢官网 22亚洲必赢官网 23

(5) 最终调用类型构造器的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节讲的反光相关文化对该类型进行操作了,那里当然是二个简短的花色,倘使想创立复杂的档次,比如有法子,事件等成员,那能够表明您的汇编能力来日趋折腾啊,也足以体会一下及时汇编制程序序员们的苦逼!托管下的汇编编码已经很简化了,围绕Emit方法折腾死!假如想研商IL,能够用IL
DASM打开托管程序集,稳步欣赏吧。

亚洲必赢官网 24亚洲必赢官网 25

在大家的壹般性支出中,有时用了动态类型也许很便宜的,比如当您要创设二个DataGrid的多寡源DataTable,但有点列不分明,列的数据类型不分明,列名也不显明的景况下,那时依据须求成立八个动态类型,继而再成立2个该类型的集纳就很方便使用了。小编封装了一个动态创立类型的类,在本文的末梢提供下载,喜欢的能够拿去。

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

 

第一个档次调用如下:

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

亚洲必赢官网 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大切诺基会每种检查参数的数据类型,无论是传入照旧回到,都有望展开大气的类型转换,那也风险了品质。所以对于反射的应用,应该小心。当然,像一些O帕杰罗M等框架是以捐躯品质来换取方便的开发体验就另当别说了。

运作结果如下:

 

亚洲必赢官网 28

转自:

5.本节中央:

本节根本介绍和反光的用途及反光的主干操作类及质量方法,下节持续深切介绍怎么样将反射技术运用于实际项目里面。

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

再次回到目录

<假使对您有帮助,记得点一下推荐哦,如有

**有不晓得或不当之处,请多调换>**

<对本类别小说阅读有困难的情侣,请先看《.net面向对象编制程序基础》>

<转发评释:技术须求共享精神,欢迎转发本博客中的小说,但请评释版权及URAV四L>

.NET
技术交换群:46718953三

亚洲必赢官网 29

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

网站地图xml地图