应用反射将枚举绑定到下拉框,中的反射

By admin in 4858.com on 2019年3月27日

序言:反射(Reflection)是.NET提须求开发者的三个无敌区工作具,固然作为.NET框架的使用者,很多时候不会用到反射。但在局地状态下,越发是在支付一些基础框架或集体类库时,使用反射会使系统架构尤其灵活。

引言

反射是.Net提供给我们的一件强力武器,即便多数状态下大家不常用到反射,即使大家恐怕也不供给了解它,但对反射的施用作以初步询问在后头的开发中只怕会怀有帮忙。

反射是三个硕大的话题,牵扯到的知识点也很多,包蕴程序集、自定义本性、泛型等,想要完全控制它万分不易。本文仅仅对反射做三个大概介绍,关于它更深邃的始末,须求在实践中渐渐控制。本文将分为下边多少个部分介绍.Net中的反射:

  1. 序章,作者将透过二个例证来引出反射,获得对反射的第①影像。
  2. 反射开头、Type类、反射普通品种。(修改中,近年来宣布…)
  3. 反射特性(Attribute)。
  4. xxxx (待定)

摘 要

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

 

序章

假诺您还平素不接触过反射,而我未来就下一堆定义告诉您哪些是反光,相信您肯定会有二头一棒的觉得。小编一向觉得这些公理式的概念和概念只有在你尽量理解的时候才能较好的发挥功效。所以,我们先来看二个付出中常遇到的难点,再看看哪些运用反射来化解:

在开始展览数据库设计的经过中,常常会创建部分基础新闻表,比如说:全国的都市,又也许订单的情形。要是大家将城市的表,起名为City,它一般包涵类似那样的字段:

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

其一表将供广大其余表引用。假若大家在确立3个酒店预约系统,那么酒馆音讯表(Hotel)就会引用此表,用CityId字段来引用宾馆所在城市。对于都市(City)表那种情况,表里存放的记录(城市消息)是不定的,意思便是说:我们可能随时会向那张表里添加新的城市(当有个别城市的首先家酒吧想要加入预约系统时,就需求在City表里新添这家酒吧所在的城池)。此时,那样的规划是合理的。

反射,四个很有用且妙趣横生的特色。当动态成立某个项目的实例或是调用方法可能访问对象成员时一般会用到它,它是遵照程序集及元数据而工作的,所以这一章我们来切磋一下程序集、反射怎样工作、怎么着动态成立类型及对象等有关文化,甚至能够动态成立程序集。

本节导读:本节最首要介绍怎么样是.NET反射性情,.NET反射能为我们做些什么,最终介绍两种常用的反射的落到实处格局,通过对反射性特的问询,能够安插出卓殊实用的依据反射的编制程序情势。

在开发中,大家常常会遇上比如说某些景况值在概念好后大约平素不改动,那时候使用数据库就显示略微多余了。首先想到的2个办法可能是在先后中创造八个数组来表示,此时,大家相见了选用数组大概带来的首先个难点:不方便使用。当数组结构改变时,大概意味着全部应用过此数组的地方的目录都发生了改变,那是我们不想见见的。

1.建表及其难点

咱俩再看看此外一种情形,大家必要标识商旅预约的图景:未提交、已交给、已吊销、受理中、已退回、已订妥、已过期。此时,很多开发人士会在数据库中国建工业总会公司立一张小表,叫做BookingStatus(预约情状),然后将如上景况进入进来,就恍如那样:

4858.com 1

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

而在先后中调用那几个表时,平日是那种情景:大家必要依照预定景况对订单列表进行筛选。此时无独有偶的做法是运用2个下拉菜单(DropDownList),菜单的数据源(DataSource),大家能够很随意地经过三个SqlData里德r获得,大家将DropDownList的文本Text设为Status字段,将值Value设为Id字段。

此刻,我们应有已经发现标题:

  1. 比方我们还有航班预约、游船预约,或许其余部分景色,大家须要在数据库中创立很多好像的小表,造成数据库表的多少过多。
  2. 咱俩利用DropDownList等控件获取表内容时,要求接二连三到数据库实行询问,潜在地影响属性。

与此同时,咱们也注意到三点:

  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从1伊始。

大家先看它化解了怎么:下边提到的题材① 、问题2都化解了,既不必要在数据库中创造表,又无需接二连三到数据库进行查询。

咱俩再看看当大家想要用文件呈现饭馆的订购时,该怎么办(假诺有订单类HotelOrder,其特性StatusId代表订单状态,为int类型
)。

// GetItem用于获取三个酒家订单对象, 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);     // 删除订单
}

此刻的标题和上面包车型客车近乎:我们需求手动输入字符串“已过期”,此时Vs2006的智能提醒发挥不了任何功能,如若我们不幸将状态值记错,可能手误打错,就将导致程序错误,较为稳当的做法如故按下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值相同,那明摆着不是我们想要的,如何是好呢?大家能够给下拉列表写1个数目绑定的事件处理方法。

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的文件格式,CLHighlander其实就是COM,相当于2个虚拟机(当然那一个虚拟机可以配备到任意帮助它的系统环境中),在安装.NET
Framework时,CL卡宴的零部件与别的COM一样在Windows系统中存有同等的对待,当CLLX570运维初阶化时会创立一个选择程序域,应用程序域是一组先后集的逻辑容器,它会趁机进度的告一段落而被卸载销毁,CL凯雷德把程序代码所须要的先后集加载到日前(或内定的)应用程序域内。CLHighlander能够以其开头化时创制的利用程序域为根基再创立其余的新利用程序域,四个利用程序域中的代码无法直接访问,当然可以经过“中介”进行数量传送。新的程序域创造完后CL逍客完全能够卸载它,以联合形式调用AppDomain.Unload方法即可,调用此方法后,CL陆风X8会挂起方今进程中的所无线程,接着查找并暂停止运输转在将要卸载的程序域内的线程,然后开始展览垃圾回收,最后主线程复苏运营。

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

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

3.枚举会同难题

可是不幸的事又生出了…
大家的订货程序分成两有的:一部分为B/S端,在B/S端能够开始展览酒店订单的
创设(未提交)、提交(已交给)、撤消提交(已收回),此外还足以看到是否已订妥;一部分为C/S端,为饭馆的预购宗旨,它能够展开其余情状的操作。

这时,对于一切系统的话,应该有整个的多个状态。但对于B/S端来说,它只有未提交、已交由、已收回、已订妥 三个状态,对应的值分别为 壹 、贰 、③ 、6。

作者们回看一下上边是如何使用数组来缓解的,它存在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 二〇〇五的智能提示已经足以表明完全意义,当大家在BookingStatus后按下“.”时,能够显得出具有的事态值。

NOTE:当大家采取枚举存款和储蓄状态时,myOrder对象的StatusId最佳为BookingStatus枚举类型,而非int类型,这样操作会越发方便一些,但为了和近年来使用数组时的景观保持统一,那里StatusId仍利用int类型。

上述二种状态使用枚举都显示相当的流畅,直到我们须要绑定枚举到DropDownList下拉列表的时候:大家领略,能够绑定到下拉列表的有两类对象,一类是贯彻了IEnumerable接口的可枚举集合,比如ArrayList,String[],List<T>;一类是落到实处了IListSource的数据源,比如DataTable,DataSet。

NOTE:实际上IListSource接口的GetList()方法重临三个IList接口,IList接口又一连了IEnumerable接口。因此看来,IEnumerable是实现可枚举集合的基础,在自身翻译的一篇文章
C#中的枚举器
中,对那么些主题做了详实的议论。

可大家都通晓:枚举enum是八个大旨项目,它不会达成别的的接口,那么大家下来该怎么做呢?

别的Windows程序都足以寄宿CLPAJERO,一台机上能够设置八个本子的CL冠道。Windows在开发银行2个托管的次序时会先运维MSCorEE.dll中的1个办法,该办法在当中依据一个托管的可执行文件新闻来加载相应版本的CLHaval,CL卡宴早先完毕之后,将次第集加载到应用程序域,最终CL库罗德检查程序集的CLCR-V头音信找到Main方法并实施它。

1.什么是.NET反射?

在其实应用中,大概供给用户下拉采取那一个情形值,这时就需求大家把枚举绑定到下拉框上(此处以Combobox为例)了。大家通晓,能够绑定到下拉框列表的有三种档次:一种是贯彻了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;
 }

接下去,为了方便使用,大家再次创下制八个尤其使用这几个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个是字段的数字型值(比如1),大家一时管那个指标叫做田野先生。其次,应该存在2个可遍历的、包蕴了字段音信的对象(也正是filed)
的成团,大家权且管那些集合叫做enumFields。

那正是说,下边就足以那样去贯彻:

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

    table.Rows.Add(row);
}

那段代码很不完整,大家注意到
xxxx,它应当是包装了字段消息(只怕叫元数据metadata)的靶子的品类。而对此enum菲尔德s,它的类型应该是xxxx那么些类型的集合。那段代码是大家依照思路假想和演绎出来的。实际上,.Net
中提供了 Type类 和 System.Reflection命名空间来援救缓解大家明天的标题。

自家在后头将较详细地介绍
Type类,现在只盼望您能对反射有个第③印象,所以只不难地作以表明:Type抽象类提供了拜访类型元数据的力量,当您实例化了三个Type对象后,你能够通过它的习性和措施,获取项指标元数据音信,大概进一步获得该项目的分子的元数据。专注到此地,因为Type对象总是基于某一档次的,并且它是三个抽象类,故而大家在开创Type类型时,须求求提供
类型,大概项指标实例,可能项指标字符串值(Part.2会表达)。

创办Type对象有很二种办法,本例中,大家利用typeof操作符来展开,并传递BookingStatus枚举:

Type enumType = typeof(BookingStatus);

下一场,大家理应想方法获得 封装了字段音信的目的 的集结。Type类提供
GetFields()方法来完成这一进度,它回到三个 FieldInfo[]
数组。实际上,约等于地点大家enumFields集合的项目。

FieldInfo[] enumFields = enumType.GetFields();

今昔,我们就能够遍历这一集聚:

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四个至关心重视要的性状,《CLTucsonviaC#》一书中对.NET反射的诠释为:在我们应用程序中选取元数据来代表存款和储蓄。编写翻译程序集或模块时,编写翻译器会成立贰个品种定义表、二个字段定义表、叁个措施定义表以及任何表。而大家假设想动态调用这么些元数据表,或视为为这么些元数据创造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#
中的泛型
一文。下边包车型地铁兑现并没有设想到品质的标题,仅仅为了引出反射使用的叁个实例。

其次节 加载程序集

简单通俗的说,正是动态调用编写翻译过的主次集中的习性,字段,方法等的经过,正是反射。

 

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

无论是VS二〇〇五的智能提示,还是修改变量名时的重构成效,都选择了反光功用。在.Net
FCL中,也日常能阅览反射的阴影,那里就向我们演示一个最广泛的例证。我们领略,在CL汉兰达中总共有二种档次,一种是值类型,一种是引用类型。声澳优(Ausnutria Hyproca)个引用类型的变量并对品种实例化,会在应用程序堆(Application
Heap)上分配内部存储器,成立对象实例,然后将对象实例的内部存款和储蓄器地址重返给变量,变量保存的是内部存储器地址,实际相当于一个指针;声美素佳儿个值类型的实例变量,则会将它分配在线程堆栈(Thread
Stack)上,变量本人富含了值类型的富有字段。

现行反革命一经我们需求比较五个指标是或不是等于。当大家相比较八个引用类型的变量是不是等于时,大家相比的是这七个变量所针对的是还是不是堆上的同五个实例(内部存款和储蓄器地址是或不是同样)。而当大家相比较多个值类型变量是还是不是等于时,如何是好吧?因为变量自个儿就隐含了值类型全体的字段(数据),所以在相比时,就需求对两个变量的字段实行逐一的一定的相比较,看看种种字段的值是不是都卓殊,倘若另外贰个字段的值不等,就回去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()方法开发是会极大的。然则这些事例仅仅为了注脚反射的用处,小编想已经高达了目标。下面的代码无法完全精通也没什么,前面会再涉及。

程序集是拥有项目标聚合,它还有一个重中之重的东西正是元数据。JIT就是使用程序集的TypeRef和AssemblyRef等元数据来鲜明所引述的次第集及项目,这一个元数据包涵名称、版本、语言文化和公钥标记等,JIT便是依照那么些新闻来加载二个先后集到利用程序域中。假设要本人加载1个程序集,能够调用类型Assembly的LoadXXX种类措施。

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

选用反射遍历枚举字段

7.小结

总的来看此间,你应当对反射有了一个从头的概念(或然叫反射的一个用场):反射是一种常见的叫法,它通过
System.Reflection 命名空间 并 同盟 System.Type
类,提供了在运作时(Runtime)对于 类型和指标(及其成员)的基本信息 以及
元数据(metadata)的访问能力。

 

(1) Load重载种类

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

要遍历枚举,首先就要求三个暗含枚举每一个字段消息的靶子,这一个目的至少应当包罗七个性子,一个是字段的名称,2个是字段的值,以造福后续绑定。

该方法会遵照一定的逐一查找钦赐目录中的程序集:先去GAC中摸索(要是是2个强命名程序集),假设找不到,则去应用程序的基目录、子目录查找。假如都没找到,则抛出相当。如下代码加载程序集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
    }

(2) LoadFrom重载种类

A.枚举类型成员

 

加载钦赐程序集名称或路径的程序集,其在其间调用Load方法,并且仍是能够钦赐三个互联网路径,假使内定网络路径,则先下载该程序集,再将其加载到程序域,如下代码:

B.实例化新目标

效果:4858.com 2

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

C.执行对象成员

此间差不多做贰个认证:Type抽象类提供了走访类型元数据的能力,当实例化了八个Type对象后,能够由此它的习性和艺术,获取项目标元数据的音信,可能进一步赢得该品种的积极分子的元数据新闻。注意到此地,因为Type对象总是基于某一现实品种的,并且它是一个抽象类,所以再创立Type类型时,供给提供项目名称也许项指标实例。程序集元数据,通过Type类型就能够访问类型的元数据新闻,而访问类型元数据的操作,就叫做反射。

(3) LoadFile重载体系

D.查找类型音信

 

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

E.查询程序集音信

使用泛型来完毕代码重用

在贰个门类中,或许程序集以内都有依靠关系,也足以将三个先后集作为财富数量嵌入到3个主次集中,在急需时再加载该程序集,那时通过注册ResolveAssembly事件来加载这几个程序集。如下;

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

观看地方的代码,固然以后有另三个枚举,叫做TicketStatus,那么要将它的枚举项文件和值转换为DataTable,唯一供给变更的便是此处:

4858.com 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的点子更改为泛型方法:

4858.com 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凯雷德会抛出很是。

A.利用反射创动态创立程序集的API文书档案。基于反射允许枚举程序集中类型及成员的性情,我们得以通过反射获取已编写翻译的先后集中的字段方法属性事件和她俩的XML注释。从而动态创制造进度序集的API文书档案;

 

B.非不时用的反射工厂形式。反射工厂情势在设计方式中相比易于领会,也比较简单。很多代码生成器中就动用那种设计格局达成不相同数据库的反光调用。比如大家有MsSql、MySql、Oracle那三种数据库,在品种规划中,大家有恐怕随时换另一种数据库,由此须要同时实现那两种数据库的底蕴增加和删除改查的类即数据访问类。我们要切换数据库的时候,只必要在config中改变数据库类型,别的的干活付出反射工厂类去动态调用编写翻译好的次序集中对应的数据库访问方法。

第三节 反射

比方没有知晓也没提到,那里只是说Bellamy(Bellamy)下反光的使用实例,以便于更有信念的上学反射。反射在设计情势中的应还有不少,那里不再列举。

咱俩通晓,在程序集(或模块)内有一个很重点的数目便是元数据,它们描述了品种定义表,字段定义表,方法表等,也便是说全部的门类及成员定义项都会在那边被清楚详细地记录下来。很显眼,若是大家获得了这个“描述新闻”,当然就一定于已经鲜明知道了一个品类及其成员,进而就足以“构造”那么些种类,通过反射就能够实现那样的目标。另人高兴的是我们不用分析这些元数据就足以便宜地获得程序集内的项目成员,.NET
Framework提供了部分与此相关的类定义在命名空间System.Reflection下。

3.反光应用基础

反射提供了打包程序集、模块和类其他靶子(Type
类型)。反射机制运维在程序运转时动态发现项目及其成员。

地方说了那般多,无非正是先让大家知道反射能为大家做些什么,上边进入正题,说一下反光的代码落成。

(1)查找程序集内所定义的档次

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

在将某一程序集加载到利用程序域后,能够由此Assembly的GetExportedTypes方法来收获该程序集全体的公开类型,如下代码:

反射的命名空间:System.Reflection

4858.com 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

4858.com 6

以此类是反射的着力,其质量方法能够拿走周转时的音信。

(2)查找类型成员

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

在命名空间System.Reflection中有3个华而不实类型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()方法:

赢得证明该成员的类或接口的门类

4858.com 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");
        }

取得成员的花色,那一个值用于指示该成员是字段、方法、属性、事件、或构造函数

4858.com 8

那是三个枚举,它定义了用来表示差别成员的类型值。那几个值包括: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

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

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

4858.com 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);
        }

成员的名目

4858.com 10

TypeReflectedType

看一下调节:

反射的指标类型

4858.com 11

Type类的只读属性

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

属性

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

描述

 

AssemblyAssembly

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

赢得内定项指标先后集

若果仅仅收获类型的目的,好像意义并十分小,大家愈来愈多的是要操作对象,比如访问属性,调用方法等,这一节大家来看一下如何访问成员。

TypeAttributesAttributes

连串Type提供了3个访问指标项目成员的不得了可相信的艺术InvokeMember,调用此措施时,它会在品种成员中找到对象成员(那平日钦点成员名称,也得以钦定搜索筛选标准BindingFlags,就算调用的靶子成员是方法,还能够给艺术传递参数。),要是找到则调用指标措施,并赶回指标访问归来的结果,借使未找到,则抛出10分,假诺是在目的措施内部有相当,则InvokeMember会先捕获该越发,包装后再抛出新的那些TargetInvocationException。以下是InvokeMember方法的原型:

获取制定项目的特征

4858.com 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 传递给目标方法的参数

取得钦点项目的第③手基类型

4858.com 13

StringFullName

在上一节的终相当大家来得了什么样调用类型的构造函数来实例化贰个目的,下边包车型大巴代码演示了怎么调用对象的不二法门,其中措施Turn接收1个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类的点子

上述的言传身教都是指向普通品种,其实反射也提供了对泛型的支撑,那里只简单演示一下反光对泛型的回顾操作。比如大家有如下一个泛型类型定义:

方法

4858.com 14

描述

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

ConstructorInfo[]GetConstructors()

4858.com 15

获得内定项指标构造函数列表

以此种类很不难,类型MyGeneric内有2个办法,该格局重回带有附加信息”
Generic Name:”的称号。先来看一下哪些获取钦点参数类型为string的泛型类:

EventInfo[]GetEvents();

4858.com 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();

4858.com 17

获取钦定项目标字段列

调剂起来,看一下末段的value值:

Type[]GetGenericArguments();

4858.com 18

收获与已布局的泛型类型绑定的品种参数列表,假设内定项目标泛型类型定义,则得到类型形参。对高满堂早布局的档次,该列表就恐怕还要含有类型实参和类型形

反射泛型的时候,要先分明指标项目是泛型,在开立泛型类型实例前,必须调用MakeGenericType方法组织一个确实的泛型,该方式接收三个要钦赐泛型类型参数的种类数组,同样调用泛型方法前要调用方法MakeGenericMethod构造相应的泛型方法,此格局也接到2个钦点泛型类型的类型数组。

MethodInfo[]GetMethods();

 

获得钦点项目的方法列表

第伍节 动态成立类型

PropertyInfo[]GetProperties();

前边几节所讲述的都以基于已经存在程序集的图景下开始展览反射,.NET
Framework还提供了在内存中动态成立类型的强硬功效。大家了然程序集包含模块,模块包涵项目,类型包蕴成员,在动态创制类型的时候也是要遵从那么些顺序。动态创设类型是基于元数据的落真实情状势来完结的,这一部分被定义在命名空间System.Reflection.Emit内,有一名目繁多的XXXBuilder构造器来创建相应的档次对象。大家来看一要动态创立类型,有哪些步骤(那里只是简单演示):

获得钦赐项目标属性列表e

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

MemberInfo[]GetMembers();

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

赢得钦点项指标成员列表

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

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

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

(3) 接下来就是创设项目了:

4.反射实例

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

上边通过贰个实例来读书一下反光最中央的行使方法。

(4)
以后能够创立项指标成员了,为项目创建三个特性Name。大家驾驭属性包蕴字段和对字段的多个访问器,所以理应先创立字段,然后再成立七个访问器方法,这一段是听从IL码的先后顺序来的,如下:

建立3个化解方案,包蕴多少个项目,项目ClassLibrary生成1个DLL,另3个品种是ReflectionTestGet,用于反射调用类ClassLibrary

4858.com 19

4858.com 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);

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

4858.com 21

MartialArtsMaster.cs

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

4858.com 224858.com 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

该办法重临3个Type类型。

Person.cs

类型创造完结后,大家就足以行使上一节讲的反射相关知识对该项目进行操作了,那里当然是一个简约的品种,固然想创制复杂的品种,比如有办法,事件等成员,那能够发挥您的汇编能力来日趋折腾吗,也能够回味一下随即汇编制程序序员们的苦逼!托管下的汇编编码已经很简化了,围绕Emit方法折腾死!如若想研讨IL,能够用IL
DASM打开托管程序集,稳步欣赏吧。

4858.com 244858.com 25

在大家的通常支付中,有时用了动态类型只怕很有益于的,比如当你要开创3个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

 

第一个门类调用如下:

第⑥节 应用反射时要留意的几点

4858.com 264858.com 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数组传递,CLTucson会各种检查参数的数据类型,无论是传入还是回到,都有大概开始展览多量的类型转换,那也危机了质量。所以对于反射的采纳,应该注意。当然,像有的O悍马H2M等框架是以献身品质来换取方便的开支体验就另当别说了。

运营结果如下:

 

4858.com 28

转自:

5.本节核心:

本节任重(Ren Zhong)而道远介绍和反光的用处及反光的为主操作类及质量方法,下节此起彼伏深远介绍如何将反射技术利用于实际项目里面。

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

回来目录

<假如对您有援救,记得点一下推荐哦,如有

**有不亮堂或错误之处,请多沟通>**

<对本种类小说阅读有诸多不便的恋人,请先看《.net面向对象编制程序基础》>

<转发表明:技术必要共享精神,欢迎转发本博客中的小说,但请申明版权及U奥迪Q3L>

4858.com ,.NET
技术调换群:467189533

4858.com 29

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

发表评论

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

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有