MVVM模式解析和于WPF中之兑现(六) 用依赖注入的方法部署ViewModel并注册信息

引言

映是.Net提供于咱的平桩强力武器,尽管大部分景象下我们不常用到反射,尽管我们或许啊非需会它,但针对反射的使用作以初步询问在其后的开发被恐怕会具备帮助。

映是一个庞然大物的话题,牵扯到之知识点也很多,包括程序集、自定义特性、泛型等,想只要了掌握其非常不易。本文只针对反射做一个大概介绍,关于她还高深的情,需要在实践中逐渐控制。本文将分为底几乎个部分介绍.Net中的照:

  1. 序章,我用由此一个例子来引出反射,获得对反射的第一印象。
  2. 照初步、Type类、反射普通档次。(修改中,近期发布…)
  3. 照特性(Attribute)。
  4. xxxx (待定)

MVVM模式解析和在WPF中的实现(六)

序章

要你还从未沾了反射,而自己现就是下同样堆定义告诉您呀是反光,相信你一定会时有发生一头一硬的发。我一直当那些公理式的定义跟定义只有以公尽知晓的时节才能够比好的发挥作用。所以,我们先行来拘禁一个付出被时常遇的问题,再看如何行使反射来化解:

以展开数据库设计的历程中,常常会起有基础信息表,比如说:全国的城市,又或者订单的状态。假设我们拿市的发明,起名为City,它便含类似这样的字段:

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

此表将供广大其他表引用。假如我们于起一个酒楼预订系统,那么酒店信息表(Hotel)就会引用此表,用CityId字段来引用酒店所在城市。对于城市(City)表这种场面,表里存放的笔录(城市信息)是勿肯定的,意思就是是说:我们恐怕随时会于当时张表里添加新的城市(当某个城市的首先下酒店想只要进入预订系统不时,就待在City表里新增补这家酒店所当的都市)。此时,这样的宏图是情理之中之。

据此依赖注入的点子部署ViewModel并注册信息

一系列目录:

MVVM模式解析及以WPF中之实现(一)MVVM模式简介

MVVM模式解析及当WPF中的贯彻(二)数据绑定

MVVM模式解析和在WPF中的兑现(三)命令绑定

MVVM模式解析和当WPF中之落实(四)事件绑定

MVVM模式解析及于WPF中之兑现(五)View和ViewModel的通信 

MVVM模式解析和在WPF中的实现(六)用依赖注入的法门部署ViewModel并登记信息

1.建表及其问题

我们再次看另外一栽情形,我们得标识酒店预订的状态:未提交、已交付、已收回、受理中、已退回、已订妥、已过。此时,很多开发人员会以数据库中成立平等摆设小表,叫做BookingStatus(预订状态),然后用使齐状态进入进来,就接近这样:

图片 1

宛如城市(City)表一样,在系统的别样表,比如说酒店签订单表(HotelOrder)中,通过字段StatusId引用这表来获取酒店预订状态。然而,几个月以后,虽然看起来与城市表底用法一样,结果也发现此表只在数据库做并查询或者
只以次中调用,却并未做修改,因为预订流程规定下后一般是勿见面转的。在应用程序中,也未会见受用户提供针对性这发明记录的增删改操作界面。

假定在次中调用这个表时,经常是这种场面:我们要根据预订状态对订单列表进行筛选。此时便的做法是采取一个下拉菜单(DropDownList),菜单的数据源(DataSource),我们可以很自由地经一个SqlDataReader获得,我们拿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. 这发明几乎从未改动。

0x00 最初的想法

这次要讨论下叫View指定ViewModel的政工。一般的话给View指定ViewModel常因此之主意来一定量种,一栽是在View的后台代码中描绘DataContext
= new
ViewModel(),还有雷同种是当XAML中指定View的DataContext。这简单栽方式还叫View对ViewModel产生了赖,这种情形下得以考虑就此依赖注入的措施如取消View对ViewModel的直依赖。依赖注入一般的话可以透过构造函数注入、通过设置属性注入,这点儿栽办法对于View来说都无相宜。因此可用IoC
Container,让View主动去取相应的ViewModel。

骨子里吃View指定一个ViewModel并无属频繁之操作,而且转移起来呢够呛容易,费半天劲为个因注入确实无绝至于。就比如上篇稿子中丢掉了大体上龙强干了个View和ViewModel的通信同,用到之概率比粗,而且为生别的艺术缓解,虽然那种方式并无切合MVVM模式。不过View除了因ViewModel之外对信息注册器也是碰头来依赖的,而且某种类型的View一般的话都依赖固定类型的ViewModel和信息注册器,因此得以一如既往软注入两独依靠,这样一般就是价值了,至少我以为是价值了,所以发生了ViewModelManager这个仿佛。

2.数组及其问题

察觉及这样设计有问题,我们本虽想方缓解其。我们所想到的首先个点子是可在次中开创一个数组来代表预订状态,这样我们就是足以删掉BookingStatus状态表(注意得这么做是以BookingStatus表的始末规定后几乎无改动)。

string[] BookingStatus = {  
   “NoUse”,
“未提交”,”已提交”,”已取消”,”受理中”,”已退回”,”已订妥”,”已过期”
};     //
注意勤组的0号元素就是打一个占位作用,以要程序简洁。因为StatusId从1起。

我们先押它们解决了什么:上面提到的问题1、问题2且解决了,既无欲在数据库中创造建表,又管需连续到数据库进行查询。

咱们重探当我们想只要就此文件显示酒店的订座时,该怎么开(假设有订单类HotelOrder,其特性StatusId代表订单状态,为int类型
)。

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

目前为止看上去还不错,现在我们需要展开一个操作,将订单的状态改呢“受理中”。

myOrder.StatusId = 4;

很丧气,我们发现了使用数组可能带来的率先只问题:不方便使用,当我们需要更新订单的状态值时,我们要去查看BookingStatus数组的定义(除非你耿耿于怀有状态的数字值),然后根据状态值在多次组吃之职位来叫目标的性能赋值。

咱们更看其他一个操作,如果某个订单的状态吧“已逾期”,就设对其进行删减:

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

这儿之题目同上面的接近:我们需要手动输入字符串“已过期”,此时Vs2005
的智能提醒发挥不了其余作用,如果我们不幸将状态值记错,或者手误打错,就用招致程序不当,较为稳妥的做法还是按下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();         
    }
}

这么,我们运用数组完成了我们愿意的力量,虽然这样实现亮略微累,虽然还存点提到的莫便于使用的题材,但这些题材我们耐心细致一点即便能战胜,而软件开发几乎从就无100%周的解决方案,那咱们简直就是这么好了。

NOTE:在ddlStatus_DataBound事件备受,引发风波之目标sender显然是DropDownList,但是此间倒是并未以sender转换成DropDownList,而是以她换成基类型ListControl。这样做是为了还好地拓展代码用,ddlStatus_DataBound事件处理方法将不仅仅限于
DropDownList,对于持续自ListControl的旁控件,比如RadioButtonList、ListBox也得不加改动地行使ddlStatus_DataBound方法。

    如果你对事件绑定还非熟识,请参考
C#遭逢的信托以及波
一文。

    这里呢足以使Dictionary<String,
Int>来成功,但都留存类似的问题,就不再举例了。

0x01 ViewModel和MessageManager的依注入

行使静态类ViewModelManager来当作IoC
Container。往IoC
Container里注册依赖关系一般有一定量栽办法,一种植是拿借助关系因某种形式(例如xml)保存于表面,一栽是在程序中注册及一个列表里。我以第二种做法,因为正如便于:)

次在启动时采用ViewModelManager.Register将凭借关系注册及ViewModelManager中,View在构造函数中调用ViewModelManager.SetViewModel(this);来安装View的DataContext并通过依赖之音信注册器注册信息,消息注册器可以呢空,代表View不收信息。它们的关系如图所示:

 图片 2

急需征的发生有限独地方:

一个是View和ViewModel的照应关系。一般的话一个View对许正在同一种ViewModel,这样注册起来是尚未问题之。但这并无绝,理论及的话一个View可以将DataContext设置也擅自ViewModel,如果一个View可以装多ViewModel该如何处理吧,这时候可以于ViewModelManager注册时上加Token属性,然后用SetViewModel(this,token)的法指定特定的ViewModel为DataContext。

别一个凡是信注册之范围。因为一般的话ViewModel都是与绑定的View通信。所以默认情况下,消息注册到独一个MessageManager中,这个MessageManager保存ViewModel中,ViewModel使用是MessageManager发送消息,发送的音信由View接收。但如果要与其余View通信,需要将信息注册到MessageManager.Default中,这个目标是static的,要上这目的而在View设置ViewMode时这样来SetViewModel(this,isGlobalMsg:true)即可。如果ViewModel又想跟绑定的View单独通信,有时候还亟需跟别的View通信,可以以信息注册器中登记时以用独自通信的信息设置一个Group,ViewModel在殡葬信息不时加一个Group过滤一下即可。一个Group可以领略啊信的独自一个大路。

顺带一提,好吧只是顺带一提的凡,在为View注入ViewModel时,顺便把ViewModel的UIDispatcher属性设置为View的Dispatcher,虽然自己不亮这生啊用。但诸如此类以ViewModel中动用UIDispatcher时就算为有关的View的Dispatcher。如果一旦下MainWindow的Dispatcher可以透过DispatcherHelper.Dispatcher或者App.Current.MainWindow.Dispatcher获得。

3.枚举及其问题

只是不幸之行同时发出了…
我们的订座程序分成两片:一部分吧B/S端,在B/S端可以展开酒店订单的
创建(未提交)、提交(已交由)、取消提交(已收回),另外还可见见是免是都订妥;一部分吗C/S端,为酒店的订货基本,它可拓展任何状态的操作。

此刻,对于任何系统的话,应该出任何的7个状态。但对于B/S端来说,它不过来
未提交、已交给、已收回、已立下妥 四个状态,相应的值分别吗 1、2、3、6。

咱们回想一下端是什么样运用数组来缓解之,它存在一个短:我们默认地拿订单状态值和数组的索引一一对许地沟通了起。

为此当绑定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>;一看似是落实了IListSource的数据源,比如DataTable,DataSet。

NOTE:实际上IListSource接口的GetList()方法返回一个IList接口,IList接口又累了IEnumerable接口。由此看来,IEnumerable是落实而枚举集合的功底,在本人翻译的一样首稿子
C#未遭之枚举器
中,对这主题做了详细的议论。

但是我们且清楚:枚举enum是一个基本类型,它不会见促成任何的接口,那么我们下该怎么做啊?

0x02 写在终极

到这个结束我能够体悟的MVVM框架的功力算是基本实现了,遇到的要求异常片,才会啊要命星星,能想到的即这几个了,欢迎回复讨论,也欢迎加我QQ16141860交流。之前一直是于TestArea这个库房里展开测试,现在夫有些框架整理了下,放到AyxMVVM仓库里了。现在有点想法还未绝成熟,使用过程被相遇题目吗会见天天修正,以后就都改及AyxMVVM中了,TestArea中之MyMVVM不再维护了。另外被仓库由名真是桩小事,干脆统一且用Ayx+XXX的方式,这样既容易再的概率又异常略带。Ayx是自家名字拼音的首字母,想想看因为拼音A开头的姓氏氏的少就能够想到几乎无见面并发又了。最后,10月6日看了微软的秋产品发布会后信教充值成功。对UWP十分谢谢兴趣,下一致步打算攻读一下。

4.以反射遍历枚举字段

最笨也是最为简易的艺术,我们好事先创造一个GetDataTable方法,此方依据枚举的字段值和数字值构建一个DataTable,最后回到这个构建好的DataTable:

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

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

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

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

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

     return table;
 }

接下去,为了方便使用,我们重创一个专程以这DataTable来装列表控件的法门SetListCountrol():

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

本,我们便得当页面中如此夺用枚举绑定到列表控件:

protected void Page_Load(object sender, EventArgs e)
{
    SetListControl(ddlStatus);   // 假设页面中一度发出ID为ddlStatus
的DropDownList
}

如果持有的枚举都要由此这样失去绑定到列表,我认为还非使以数据库中一直建表,这样事实上是绝累了,而且我们是因枚举的文本及值去HardCoding出一个DataTable的:

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

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

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

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

斯时,我们怀念有没有起方法通过遍历来兑现此?如果想使遍历这里,首先,我们用一个含有枚举的每个字段信息之目标,这个目标至少含有两长条消息,一个凡是字段的文书(比如“未提交”),一个凡字段的数字型值(比如1),我们小还不论这个目标叫做field。其次,应该留存一个可是遍历的、包含了字段信息的对象(也就算是filed)
的成团,我们临时还无是集叫做enumFields。

那,上面就足以如此夺落实:

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

    table.Rows.Add(row);
}

随即段代码很无整,我们注意到
xxxx,它应当是包裹了字段信息(或者叫元数据metadata)的靶子的类。而对enumFields,它的路应该是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);
    }
}

这里field的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, field.Name);
//也堪这么

            table.Rows.Add(row);
        }
     }

     return table;
 }

留神,SetListControl()方法还是存在并中,只是以节约篇幅,我并未复制过来,它的应用以及事先是同样的,我们只是修改了GetDataTable()方法。

0x03 关于AyxMVVM

https://github.com/durow/AyxMVVM

5.动泛型来上代码用

观察地方的代码,如果我们现发生其它一个枚举,叫做TicketStatus,那么我们要以它绑定到列表,我们唯一需要变更的尽管是此处:

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

既然如此这样,我们何不定义一个泛型类来进展代码用呢?我们随便这泛型类叫做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, field.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 中反射的一个范例。

不论是VS2005之智能提醒,还是修改变量名时的重构功能,都用了照作用。在.Net
FCL中,也时能看出反射的影,这里虽往大家演示一个不过常见的事例。大家理解,在CLR中累计发个别栽档次,一栽是值类型,一种植是援引类型。声明一个援类型的变量并对项目实例化,会以应用程序堆(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()方法开发是会见生死之。但是这例子只是为验证反射的用,我怀念就上了目的。上面的代码不克全知道吧没什么,后面会还涉及。

7.小结

瞧此间,你当本着反射出了一个发端的概念(或者为反射的一个用场):照是一致种植常见的叫法,它经过
System.Reflection 命名空间 并 配合 System.Type
类,提供了当运作时(Runtime)对于 类型和目标(及其成员)的中坚信息 以及
元数据(metadata)的访能力。

 

发表评论

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

网站地图xml地图