<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Evil 域</title><subtitle type="text">当Evil遇上先知</subtitle><id>http://feed.cnblogs.com/blog/u/26363/rss</id><updated>2011-11-23T03:12:57Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/26363/rss"/><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/11/23/2258456.html</id><title type="text">LightSwitch 2011 实践之个人汽车仓库 —— 起步</title><summary type="text">LightSwitch 2011发布，它介乎于Excel和Visual Studio之间，小投入，快速的开发出以数据为中心应用程序，表达关系比Excel灵活。经过两三天的学习，外加三个小时的实践，编写了一个小系统，把过程拿出来跟大家分享（很多地方有待改进，但已经可以初步使用了。）</summary><published>2011-11-23T03:13:00Z</published><updated>2011-11-23T03:13:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/23/2258456.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/23/2258456.html"/><content type="html">&lt;p align="center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055428867.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055453586.png" border="0" height="324" width="524" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;（图片来自Bing图片搜索）&lt;/p&gt;  &lt;p&gt;最近，从加拿大辗转来到美国快两个月了，发现没有车的美国生活真是悲惨啊。嗯，是时候下决心买车了。预算有限，打算买辆二手车。于是着手上网查资料。找到了几个比较著名的二手车的论坛，资料虽然不少，但是，数据不集中。总打算着把数据收集下来，形成一个&lt;strong&gt;虚拟的&lt;/strong&gt;、个人的汽车仓库。&lt;/p&gt;  &lt;p&gt;本打算用Excel来做，但发现Excel在表现关系的时候有一定的问题，例如，记录Dealer与汽车之间的关系，要么每一个Dealer一个Page，不利于数据搜索；要么就是每一行数据上都放上车行域，冗余数据比较多，而且不利于保持数据的一致性。&lt;/p&gt;  &lt;p&gt;于是，萌生了用Visual Studio配合数据库来做一个管理软件的想法。但是，由于业余时间有限，而且这个系统等买完车了以后可能就不再用了，投入产出不成比例。（Access似乎也是一个选择，不过我对Access不是很懂）。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;此时正好赶上LightSwitch 2011发布，发现它介乎于Excel和Visual Studio之间，相对于Visual Studio来说，小投入，快速的开发出应用程序，表达关系又比Excel灵活。经过两三天的学习，外加三个小时的实践，初步把Dealer和Car的模块做好了（很多地方有待改进，但已经可以初步使用了。）&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;运行效果&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055489386.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055504171.png" border="0" height="364" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;（点击看大图）&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;准备工作&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;准备工作很简单，下载LightSwitch，&lt;a title="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=26830" href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=26830"&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=26830&lt;/a&gt;并且安装。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;模型设计&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055531332.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055552006.png" border="0" height="371" width="503" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;（图片来自Bing图片搜索）&lt;/p&gt;  &lt;p&gt;这里的模型是指数据模型。在模型设计过程中，要识别出系统中的两个部分，一个是&lt;strong&gt;实体&lt;/strong&gt;，另一个是各个实体之间的&lt;strong&gt;关系&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;em&gt;（在话在哪儿听过？大概可能也许或者是关系型数据库设计课程上吧^o^）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;简单的说，实体可以看成是生活中具体的事物。例如，我想收集、管理的数据包括Vehicle的和Dealer的两部分，因此，在我的数据模型里，有两个实体：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Vehicle&lt;/li&gt;    &lt;li&gt;Dealer&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;关系无外乎三种：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;一对一&lt;/li&gt;    &lt;li&gt;一对多&lt;/li&gt;    &lt;li&gt;多对多&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;例如，一个Dealer下面可以有好多部我感兴趣的车，而每一部车物理上只属于一个Dealer，所以它们之间是1对多的关系。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;想法确定了以后，就可以动手了。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;创建模型&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;首先，创建一个LightSwitch应用程序。给程序取个又好听又好记的名字或者代号，例如PCI(Personal Car Inventory)。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055563793.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221055585821.png" border="0" height="664" width="959" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;在程序创建以后，我们可以在主界面上选择Create new table来&lt;strong&gt;创建实体&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056006396.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056043491.png" border="0" height="752" width="1008" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;首先，我们把Table1Item改成Vehicle。并且加一系列的汽车相关的&lt;strong&gt;属性&lt;/strong&gt;。请大家看图。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056054995.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056074863.png" border="0" height="456" width="597" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;其中，A处即实体名称。&lt;/p&gt;  &lt;p&gt;第一行C处是系统生成的域，其作用是充当数据库中的主键，用于&lt;strong&gt;唯一标识&lt;/strong&gt;一行记录。它是一个自增的整数编号；&lt;/p&gt;  &lt;p&gt;VIN是&lt;strong&gt;Vehicle的唯一标识编号&lt;/strong&gt;，就像人的身份证号一样，因此，根据这个号即可确定是哪一辆车，B处，我们把它设置成必须；&lt;/p&gt;  &lt;p&gt;&lt;em&gt;（我们可以顺手把它设置成不可重复，方法大家自己猜吧^o^）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;其它的属性都是浮云&amp;#8230;&amp;#8230;（根据需要添加、删减）&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;然后，我们通过界面上的菜单，再添加一个车行的实体。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056081666.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056105961.png" border="0" height="302" width="1005" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;同样，修改实体名称，添加属性。跟Vehicle一样。唯一有趣的是，大家会发现，这里有两个有趣的数据类型，分别是&lt;strong&gt;电话号码&lt;/strong&gt;和&lt;strong&gt;电子邮件&lt;/strong&gt;格式。（呵呵，LightSwitch想得周到啊，省去了满世界找正则表达式来作验证的功夫了。^o^）&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056111369.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056143024.png" border="0" height="548" width="825" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;接下来，就可以&lt;strong&gt;添加实体间关系了&lt;/strong&gt;。选中其中任何一个实体，点击设计器上方的Add Relationship按钮。&lt;/p&gt;  &lt;p&gt;根据前面的设想，我们选择从Dealer到Vehicle的一对多的关系。&lt;/p&gt;  &lt;p&gt;当Dealer下面有车时，我们不允许删除，因此，On Delete行为我们选择Restricted。&lt;/p&gt;  &lt;p&gt;&lt;em&gt;如果允许删除有汽车记录的Dealer的记录，那么可以选择Cascade，但要当心，这样子，车行下所有的汽车记录也会被同时删除。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Multiplicity我选择了Zero or one对多，而不是单纯的一对多。这是考虑到在添加Vehicle记录时，我可能还没有Dealer的信息。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056154528.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056168856.png" border="0" height="488" width="504" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;这样，我们的数据建模就完成了。如果我们现在F5调试，会看到一个UI的架子，但是，没有任何跟我们的模型有关系的、并且可以操作的内容。因此，我们需要一些UI来提供用户（也就是我自己）操作。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;生成界面&lt;/strong&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056204839.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056241345.png" border="0" height="379" width="504" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;/p&gt;  &lt;p align="center"&gt;（图片来自Bing图片搜索）&lt;/p&gt;  &lt;p&gt;生成？没错，&lt;strong&gt;生成&lt;/strong&gt;！一旦数据模型好了以后，我们就可以生成界面了。&lt;/p&gt;  &lt;p&gt;在添加关系的按钮的右边，有一个添加Screen的按钮。点击一下，我们看到一个生成UI的向导。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056269784.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056277700.png" border="0" height="539" width="745" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在向导左边，我们可以选择可以生成的窗口的类型。由于我想要一个汽车的列表，并且，这个列表需要带搜索功能。因此，在此，我选择Search Data Screen。并且给窗口取个名字，例如SearchVehicle。Screen Data当然是选择Vehicles啦。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056291439.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056317827.png" border="0" height="574" width="804" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;然后我们看到了&amp;#8230;&amp;#8230;一个树状结构-.-||。OK，让我们F5调试，试试看。这次比上次啥都没有看到好，至少，我们看到一个叫Search Vehicle的窗口了。但是，我们似乎还是不能添加汽车记录。因此，我们需要修改界面，增加一个添加记录的按钮。SwitchLight提供了&lt;strong&gt;运行时调整界面&lt;/strong&gt;的功能。点击右上角Design Screen，我们看到了跟设计器类似的一个UI树。它就是我们UI的结构。&lt;/p&gt;  &lt;p&gt;展开Data Grid的下面的Command Bar（不是Data Grid Row或者是其它地方的），点击Add，然后选择AddAndEditNew。&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056328011.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/20111122105636123.png" border="0" height="646" width="824" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;AddNew和AddAndEditNew的区别是，AddNew只添加一条空的记录，而AddAndEditNew还会直接打开一个界面让我们给新添加的记录填写内容。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;点击Save以后，界面上是不是多了一个&lt;strong&gt;绿色加号&lt;/strong&gt;按钮？这样，我们就可以添加汽车记录了。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056382400.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111221056431000.png" border="0" height="772" width="985" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;用添加AddAndEditNew按钮的方法，添加删、改按钮以后，我们就有了一个可以对汽车记录进行增删改查的系统了。&lt;/p&gt;  &lt;p&gt;同样的方法，可以生成一个管理Dealer的界面。&lt;/p&gt;  &lt;p&gt;呵呵，这样，一个管理汽车和Dealer的系统便基本成型了。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;经过一些努力，我们构建了一个数据模型并且得到了一个很粗糙的系统。对于以数据为中心的程序的开发，LightSwitch是比较高效的。&lt;/p&gt;  &lt;p&gt;系统还在继续开发中，LightSwitch还有很多有趣的东西。大家不妨自己下载一个LightSwitch自己试试开发一个自己的系统。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2258456.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/23/2258456.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/11/01/2230935.html</id><title type="text">让我们更快一点的Visual Studio的技巧们</title><summary type="text">积跬步以至千里。积小流以成江海。它们只是不起眼的小技巧。日积月累，它们让我们的工作、学习更有效率，让我们更加专注于逻辑本身，它们是.NET程序员的好朋友，它们是Visual Studio的小技巧……</summary><published>2011-10-31T23:16:00Z</published><updated>2011-10-31T23:16:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/01/2230935.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/01/2230935.html"/><content type="html">&#xD;
&lt;p&gt;积跬步以至千里。积小流以成江海。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;它们只是不起眼的小技巧。日积月累，它们让我们的工作、学习更有效率，让我们更加专注于逻辑本身，它们是.NET程序员的好朋友，它们是Visual Studio的小技巧&amp;#8230;&amp;#8230;我们，真的认识它们吗？ &lt;img style=""  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706166755.png" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;如果想尽快掌握这些技巧，请打开Visual Studio亲自试一下这些技巧，希望找到你喜欢的技巧的。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010710026644.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010710053250.png" width="352" height="419" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;(图片来自Bing)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;让代码写得再快一些&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;怎么快速的创建一个类？创建一个应用程序，找个能建类的空地，试试这个：&lt;strong&gt;class&amp;lt;Tab&amp;gt;&amp;lt;Tab&amp;gt;&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706239376.png"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706244817.png" width="304" height="313" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;别急，这个技巧还没有完。直接输入想要的类名，然后敲回车。&lt;/p&gt;  &lt;p&gt;经常创建属性？试试&lt;strong&gt;prop&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;经常写foreach语句？试试&lt;strong&gt;foreach&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;经常写控制台应用程序？试试&lt;strong&gt;cw&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;如果有多个高亮区怎么办？用Tab跳转。&lt;/p&gt;  &lt;p&gt;怎么找到其它的Code Snippets？试试通过上下文菜单或者快捷键。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706257193.png"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706263157.png" width="410" height="434" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;让命名空间操作再快一些&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;经常写文件相关操作但悲剧的发现System.IO不在默认的引用命名空间里面？呵呵，试试这个。直接在方法中输入&lt;strong&gt;File+&amp;lt;ESC&amp;gt;+Ctrl+.+&amp;lt;Enter&amp;gt;&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706278598.png"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706285467.png" width="384" height="226" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;好吧，这个组合看上去有点复杂。让我们来看分解动作，一旦它成为了肌肉记忆，一切都将变得那么自然&lt;img style=""  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201111/201111010706166755.png" /&gt;&lt;/p&gt;  &lt;p&gt;首先，&lt;strong&gt;File + &amp;lt;ESC&amp;gt;&lt;/strong&gt;，输入类名File，&amp;lt;ESC&amp;gt;是用于消除Completion List。这时，可以看到File左下角有一个小小的蓝色的小块，这个小块说明已经有Smart Tag可用了；&lt;/p&gt;  &lt;p&gt;然后，&lt;strong&gt;Ctrl+.&lt;/strong&gt;用于打开SmartTag，通常，添加using会是第一个选项。&lt;/p&gt;  &lt;p&gt;最后，&lt;strong&gt;&amp;lt;Enter&amp;gt;&lt;/strong&gt;应用第一项。&lt;/p&gt;  &lt;p&gt;&lt;em&gt;例外：这个技巧不适用于扩展方法。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;让命名空间精简而有序&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;好吧，如果你希望你的类写完以后，让引用的命名数量变得最少并且按字母排序，你可以用下面这个组合：&lt;strong&gt;&amp;lt;Application&amp;gt;+&amp;lt;o&amp;gt;+&amp;lt;a&amp;gt;&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;不知道&lt;strong&gt;&amp;lt;Application&amp;gt;&lt;/strong&gt;键是哪一个键？我也不知道，从&lt;a href="http://www.seoconsultants.com/windows/keyboard/#Application" target="_blank"&gt;这里&lt;/a&gt;借个名称。其实就是右Ctrl键左边的那一个，用来调出上下文菜单的键。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;让继承抽象类和实现接口再快一些&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;当手上有一个抽象类，有N个抽象方法，当抽象类被继承时，重写这些方法名称费时费力又无聊&amp;#8212;&amp;#8212;像是在抄写方法名。为什么不让Visual Studio来做呢？&lt;/p&gt;  &lt;p&gt;为了方便大家动手，请把下面的代码复制、粘贴到Visual Studio中：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;abstract&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; &lt;font color="#4bacc6"&gt;Person&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;abstract&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; Walk();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;abstract&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; Eat();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;class&lt;/span&gt; &lt;font color="#4bacc6"&gt;Baby &lt;/font&gt;: &lt;font style="background-color: rgb(255, 255, 0);" color="#4bacc6"&gt;Person&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;然后把光标放到Baby后面的Person上，看到Smarttag了？那就&lt;strong&gt;Ctrl+.+&amp;lt;Enter&amp;gt;&lt;/strong&gt;吧。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;此方法同样适用于接口。&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;让重命名再快一些&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;经常为了偷懒取个比较短的变量名？有的team会不允许使用缩写作为变量名，而全称又太长，这时，可以先写短名，然后直接改名。例如，有些团队不允许单字母的变量，像这里的i：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;for&lt;/span&gt; (&lt;span &gt;int&lt;/span&gt; i = 0; i &amp;lt; 100; i++)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;System.Console.WriteLine(i + 1);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;首先，请通过&lt;strong&gt;for&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;生成for语句，然后使用&lt;strong&gt;cw&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;来生成WriteLine语句。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;然后，把光标定位在第一个i的后面，输入ndex。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;看到SmartTag的提示小块了？&lt;strong&gt;Ctrl+.+&amp;lt;Enter&amp;gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;除了给引用命名空间引用排序外，其实，我们只接触到了两个快捷键：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;Ctrl+.&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;前者主要用于插入code snippets，后者则用于调用SmartTag。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这些不是什么高深的技术，但却是写代码时天天要用到的技巧。有这些小技巧的日积月累，相信会水滴石穿。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这些技巧不能帮助你写出更出色的代码来，但是，习惯以后，它可以提升我们写代码的速度，进而让我们有更多的时间花在提高代码质量上。&lt;/p&gt; &#xD;
&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2230935.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/11/01/2230935.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/09/22/2179396.html</id><title type="text">实战 WPF Jump List 编程</title><summary type="text">本文介绍了JumpList编程的一些基础内容，并且，提供了两种Jump List编程时典型的Scenarios的实现方法 —— 单一WPF应用程序实例和进程间通讯</summary><published>2011-09-21T22:45:00Z</published><updated>2011-09-21T22:45:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/09/22/2179396.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/09/22/2179396.html"/><content type="html">&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170827578876.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828063803.png" width="582" height="693" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;（图片来自Bing搜索）&lt;/p&gt;  &lt;p&gt;Windows 7提供了JumpList，可以通过右击任务栏上的图标，跳出快捷菜单，为用户操作应用程序提供一个捷径。例如，Live Messenger为我们提供了注销和退出的功能：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828081112.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828092672.png" width="237" height="388" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;WPF为Jump List提供了支持。&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;我们来实现如下一个Jump List：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;这个JumpList有三个分组，分别是：Function，3rd Party Applications和Window Control。 &lt;/li&gt;    &lt;li&gt;Function里提供一个Hello的项，弹出一个Hello JumpList对话框； &lt;/li&gt;    &lt;li&gt;3rd Party Appliation里，我们可以直接调用计算器； &lt;/li&gt;    &lt;li&gt;Window Control里提供两个功能，另外是最大化和最小化窗口。 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;如果没有接触过Jump List的编程，现在，请花2分钟时间大概构想一下实现方法吧&amp;#8230;&amp;#8230;（2分钟过去了）&lt;/p&gt;  &lt;p&gt;来看看结果是不是跟你想像的一样。&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;基础&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;明白JumpList的结构&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;这个不多说，请大家看图：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082811329.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828127986.png" width="644" height="174" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;我们将结合WPF来看看JumpTask的开发。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;JumpList的XAML支持&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;WPF提供了叫JumpList的Attach属性来支持JumpList。大概的样子如下：&lt;/p&gt;  &lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Application&lt;/span&gt; &lt;span &gt;&amp;#8230;&lt;/span&gt;&#xD;
    &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpList.JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
            &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Say Hello&amp;quot;&lt;/span&gt; &lt;span &gt;Arguments&lt;/span&gt;&lt;span &gt;=&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span &gt;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&#xD;
        &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
    &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;JumpList.JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Application&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;仔细观察高亮的代码行，它有一个Title属性，大家一定都知道它是干什么的了。Arguments属性也可以理解，传入参数。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;读到这里是不是有一个疑问：&lt;strong&gt;为什么没有类名或者函数名称之类的？这个JumpTask将由谁哪个函数来执行呢？&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;JumpTask执行逻辑&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;卖个关子，先。请大家新建一个WPF应用程序：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;打开App.XAML，复制、粘贴从以上代码 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;在项目属性中去掉Enable the Visual Studio hosting process的对勾 &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828148707.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828152776.png" width="244" height="197" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;F5调试 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;右击应用任务栏上的图标，是不是已经看到对应的JumpList项了？ &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082816400.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828188057.png" width="237" height="166" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;点击调用Say Hello。 &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;看到了什么？没错，一个新的应用程序实例被打开了。因此，Arguments的调用者，就是应用程序本身，再精确点说，是Main函数。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;如果应用程序名叫&lt;em&gt;JumpList.exe&lt;/em&gt;，那么当用户点击Say Hello时，相当于调用了&lt;em&gt;JumpList.exe &lt;strong&gt;hello&lt;/strong&gt;&lt;/em&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;既然每次点击JumpList上的项都会&lt;strong&gt;产生一个新的应用程序实例&lt;/strong&gt;，那么如何实现让它弹出Hello JumpList的对话框？&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这里提供一种简单实现：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;我们重写App类的OnStartup方法，利用Environment.GetCommandLineArgs()方法来获取参数，如果参数为hello，那么显示对话框，然后&lt;strong&gt;马上结束当前实例&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;为了减小干扰，这里用了硬编码来读取第一个参数。实际项目慎用。&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;protected&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; OnStartup(StartupEventArgs e)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;base&lt;/span&gt;.OnStartup(e);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            &lt;span &gt;// Get all command arguments&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            var arguments = Environment.GetCommandLineArgs();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;// Execute when there are arguments other than the application itself.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (arguments.Length &amp;gt; 1)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;                &lt;span &gt;// Lower the character.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;                var argument = arguments[1];&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt; (argument.Equals(&lt;span &gt;&amp;quot;hello&amp;quot;&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;                    &lt;span &gt;// Execute when the parameter equals hello.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;                    MessageBox.Show(&lt;span &gt;&amp;quot;Hello JumpList&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;                    &lt;span &gt;// Shutdown the new instance.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;                    &lt;font style="background-color: #ffff00"&gt;App.Current.Shutdown();&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;请大家按照这个思路编写代码，看看执行效果：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828194318.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828218354.png" width="244" height="143" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;JumpTask调用第三方应用&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;根据我们对JumpList的理解，不难推测，JumpTask调用第三方应用将异常的简单，例如，我们可以通过以下代码调用计算器（calc.exe）：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Calculator&amp;quot;&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;ApplicationPath&lt;/span&gt;&lt;span &gt;=&amp;quot;calc&amp;quot;&lt;/span&gt;&lt;/font&gt; &lt;span &gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;利用&lt;strong&gt;ApplicationPath属性&lt;/strong&gt;来指定要执行的应用程序名称。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;Arguments属性仍然有效。这也就是说，如果我们把ApplicationPath指向自己，并且传入对应的参数，即可达到前一个例子的效果。&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;为JumpTask项目分组&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;对JumpTask的分组也相当简单，只要设置JumpTask项的CustomCategory属性即可。例如：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpList.JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
            &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Calculator&amp;quot;&lt;/span&gt; &lt;span &gt;ApplicationPath&lt;/span&gt;&lt;span &gt;=&amp;quot;calc&amp;quot;&lt;/span&gt;  &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;CustomCategory&lt;/span&gt;&lt;span &gt;=&amp;quot;3rd Party Applications&amp;quot; &lt;/span&gt;&lt;/font&gt;&lt;span &gt;/&amp;gt;&lt;/span&gt;&#xD;
            &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Say Hello&amp;quot;&lt;/span&gt; &lt;span &gt;Arguments&lt;/span&gt;&lt;span &gt;=&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;CustomCategory&lt;/span&gt;&lt;span &gt;=&amp;quot;Function&amp;quot;&lt;/span&gt;&lt;/font&gt; &lt;span &gt;/&amp;gt;&lt;/span&gt;&#xD;
        &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
    &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;JumpList.JumpList&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;需要注意的是，分组出现的顺序是&lt;strong&gt;从后向前&lt;/strong&gt;的。例如，上面的JumpList中，&lt;strong&gt;最后定义&lt;/strong&gt;的分组是Function，那么，在JumpList中，&lt;strong&gt;最先出现&lt;/strong&gt;的分组就是Function。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082822122.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828243668.png" width="237" height="212" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;JumpTask项的图标设置&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;JumpTask有两个属性用以控制图标：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;&lt;strong&gt;IconResourcePath&lt;/strong&gt;指向图标所在的位置 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;&lt;strong&gt;IconResourceIndex&lt;/strong&gt;设置图标的序号（0为起始序号）&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;例如：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Calculator&amp;quot;&lt;/span&gt; &lt;span &gt;ApplicationPath&lt;/span&gt;&lt;span &gt;=&amp;quot;calc&amp;quot;&lt;/span&gt;  &lt;span &gt;CustomCategory&lt;/span&gt;&lt;span &gt;=&amp;quot;3rd Party Applications&amp;quot;&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;IconResourcePath&lt;/span&gt;&lt;span &gt;=&amp;quot;%windir%\system32\calc.exe&amp;quot;&lt;/span&gt;&lt;/font&gt; &lt;span &gt;/&amp;gt;&lt;/span&gt;&#xD;
            &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;JumpTask&lt;/span&gt; &lt;span &gt;Title&lt;/span&gt;&lt;span &gt;=&amp;quot;Say Hello&amp;quot;&lt;/span&gt; &lt;span &gt;Arguments&lt;/span&gt;&lt;span &gt;=&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span &gt;CustomCategory&lt;/span&gt;&lt;span &gt;=&amp;quot;Function&amp;quot;&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;IconResourcePath&lt;/span&gt;&lt;span &gt;=&amp;quot;%windir%\System32\imageres.dll&amp;quot;&lt;/span&gt; &lt;span &gt;IconResourceIndex&lt;/span&gt;&lt;span &gt;=&amp;quot;18&amp;quot;&lt;/span&gt;&lt;/font&gt; &lt;span &gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;分别取到了计算器本身的第0个图标和imageres.dll的第18个图标。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;如果不想有图标，那就把IconResourceIndex设置成-1。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;至此，我们了解了WPF中JumpTask编程的基本内容，包括JumpList的结构，调用逻辑等。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;但是，&lt;strong&gt;从用户的角度出发，JumpList往往应该是针对当前应用实例的&lt;/strong&gt;。例如，我们列出的目标JumpList中，包括了最大化、最小化。当用户点击它们的时候，肯定&lt;strong&gt;不会期望&lt;/strong&gt;应用程序新建一个实例，并且最大化、最小化新实例。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828257944.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828266473.png" width="237" height="212" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;要实现这样的功能，需要涉及到两个常用的WPF编程技巧，分别是：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;单一应用程序实例 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;进程间交互 &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;提高&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828333296.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828428681.png" width="641" height="762" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p align="center"&gt;（图片来自Bing搜索）&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;实现思路：&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先，当用户点击JumpTask项时，如果已经有进程实例存在，那么，新实例将终止自己——即实现单一应用程序实例；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;其次，新实例终止自己前，需要告诉原有实例，用户调用了什么操作——新老进程间交互；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;我们将问题分解，分两部分实现：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;单一应用程序实例的实现&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;参考：&lt;a href="http://pietschsoft.com/post/2009/01/02/Single-Instance-WPF-Application-in-NET-3.aspx"&gt;Single Instance WPF Application in .NET 3.x&lt;/a&gt;介绍了两种实现方法：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;检查进程名——有的项目通过此方法检查安装程序，结果导致与系统进程名冲突，不推荐使用。 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;使用WindowsFormsApplicationBase——文章里有源代码，大家可以试试。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;这里另外介绍&lt;strong&gt;使用信号量（Mutex）&lt;/strong&gt;的方法，来实现WPF应用程序单一实例。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;.NET提供了Mutex类（System.Threading.Mutex），它的构造方法中有一个重载，接受一个名称，并且&lt;strong&gt;输出是否新建了信号量&lt;/strong&gt;。我们可以利用这个重载，为应用程序找一个唯一的标识。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;最容易想到的方法就是生成一个GUID。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Visual Studio自带了一个GUID在的生成器，可以通过Tools | Create GUID打开，把对应的GUID复制出来即可。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828433273.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828453438.png" width="237" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;接下来，我们在OnStartup中，创建信号量，并且在OnExit中，销毁它。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828469982.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828476734.png" width="244" height="163" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;主要代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.Threading;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.Windows;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;&lt;span &gt;namespace&lt;/span&gt; WpfApplication20&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; App : Application&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        Mutex _singleInstanceMutex;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;span &gt;const&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; _applicationGUID = &lt;span &gt;&amp;quot;38038762-99E1-4F8A-A937-1AE8A3308298&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        &lt;span &gt;protected&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; OnStartup(StartupEventArgs e)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            &lt;span &gt;base&lt;/span&gt;.OnStartup(e);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;            &lt;span &gt;bool&lt;/span&gt; isNewMutex;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;            &lt;font style="background-color: #ffff00"&gt;_singleInstanceMutex = &lt;span &gt;new&lt;/span&gt; Mutex(&lt;span &gt;false&lt;/span&gt;, _applicationGUID, &lt;span &gt;out&lt;/span&gt; isNewMutex);&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (isNewMutex)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;                &lt;span &gt;//1st instance of current application&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;            &lt;span &gt;else&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;                &lt;span &gt;// Not the 1st instance&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;                var arguments = Environment.GetCommandLineArgs();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;                &lt;span &gt;// Execute when there are arguments other than the application itself.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt; (arguments.Length &amp;gt; 1)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;                    &lt;span &gt;// Deal with the command argumens.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;                    &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;                &lt;span &gt;else&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  33:  &lt;/span&gt;                    MessageBox.Show(&lt;span &gt;&amp;quot;Sorry, only one instance of the applciation is allowed!&amp;quot;&lt;/span&gt;, &lt;span &gt;&amp;quot;Multiple Instances&amp;quot;&lt;/span&gt;, MessageBoxButton.OK, MessageBoxImage.Error);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  35:  &lt;/span&gt;                &lt;span &gt;// Shutdown the new instance.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;                App.Current.Shutdown();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  37:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  39:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;用WCF实现进程间交互&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;要实现通过JumpTask来最大化、最小化，除了不让一个以上的应用程序实例出现以外，我们还需要在新进程被Shutdown之前，告诉第一个实例的进程，进行最大化或者最小化操作。这就涉及到&lt;strong&gt;进程间交互&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;我们知道，在OS中，进程之间的资源是相互独立的。要让进程之间进行通讯，必须付出努力&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none"  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082848703.png" /&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;以前，在.NET中，我们通过Remoting来进行进程间交互。&lt;em&gt;（我们可以通过&lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/.NET_Remoting" target="_blank"&gt;&lt;em&gt;维基百科来查查Remoting&lt;/em&gt;&lt;/a&gt;&lt;em&gt;的底细&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none"  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082848703.png" /&gt;。）&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;现在Remoting已被WCF代替。我们下面就来看如何用WCF，实现最大化、最小化窗口的方法。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;你不需要太多的关于WCF的知识。如果你没有接触过WCF，那么，记住下面&lt;strong&gt;两件事情&lt;/strong&gt;和&lt;strong&gt;一些基本概念&lt;/strong&gt;就可以了：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;逻辑上，WCF分&lt;strong&gt;客户端&lt;/strong&gt;和&lt;strong&gt;服务端&lt;/strong&gt;； &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;客户端和服务端通过端点（EndPoint）进行通讯。&lt;strong&gt;ABC&lt;/strong&gt;进行通讯。什么是ABC呢？&lt;strong&gt;ABC就是Address，Binding和Contract&lt;/strong&gt;。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;这里有一些基本概念，大家留一个印象（描述并不一定很精确，大家&lt;a href="http://msdn.microsoft.com/en-us/library/ms733107.aspx" target="_blank"&gt;参考MSDN啊&lt;/a&gt;）：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;&lt;font size="5"&gt;A&lt;/font&gt;ddress：一个Uri，用于表达服务所在位置； &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;&lt;font size="5"&gt;B&lt;/font&gt;inding：定义通讯的方法，其实就是在服务端与客户端约定好，怎么通讯，是http呢还是namedpipe呢还是TCP&amp;#8230;&amp;#8230;不明白细节没有关系，只要在服务器与客户端使用一致的Binding类型即可。 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;&lt;font size="5"&gt;C&lt;/font&gt;ontract：定义服务提供的具体的方法及参数——我们往往使用.NET接口作为协议。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;有了这些基本概念以后，我们就可以着手实现功能了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先，我们要想清楚，在我们的例子中，谁是客户端，谁是服务端？&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#8230;&amp;#8230;（想ing&amp;#8230;）&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;由于是第二个应用程序实例要调用第一个应用程序实例功能（最大化、最小化），因此，&lt;strong&gt;第一个&lt;/strong&gt;应用程序&lt;strong&gt;实例&lt;/strong&gt;需要&lt;strong&gt;提供服务&lt;/strong&gt;；而&lt;strong&gt;第二个&lt;/strong&gt;应用程序&lt;strong&gt;实例&lt;/strong&gt;作为客户端来&lt;strong&gt;调用服务&lt;/strong&gt;。 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;第一个应用程序的实例的代码和第二个应用程序的实例的&lt;strong&gt;代码&amp;#8230;&amp;#8230;是同一份&lt;/strong&gt;，因此，无论是服务还是客户端代码，都应该在&lt;strong&gt;同一个项目中&lt;/strong&gt;。 &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;通过前面对单一应用程序实例的实践，我们有办法判断代码是第一个实例还是后来的实例了，因此，我们可以在第一个实例的时候作为服务端创建服务；以后每次调用服务，并结束进程。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;这样，终于可以动手了，先写服务端代码：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第一步：添加引用：System.ServiceModel和System.Runtime.Serialization。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第二步：&lt;strong&gt;实现服务&lt;/strong&gt;——编写实现最大化和最小化的&lt;strong&gt;类&lt;/strong&gt;：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MMService&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; Max()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            App.Current.MainWindow.WindowState = System.Windows.WindowState.Maximized;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; Min()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            App.Current.MainWindow.WindowState = System.Windows.WindowState.Minimized;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;第三步，抽象出&lt;strong&gt;服务接口&lt;/strong&gt;，作为&lt;strong&gt;服务协议&lt;/strong&gt;（ABC中的&lt;strong&gt;C&lt;/strong&gt;）：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;我们可以通过Visual Studio提供的重构功能，自动抽象出接口代码，然后，为接口添加协议所需要的属性：ServiceContract和OperationContract。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828502505.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/201109170828514622.png" width="244" height="111" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.ServiceModel;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;&lt;span &gt;namespace&lt;/span&gt; WpfApplication20&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;    [&lt;font style="background-color: #ffff00"&gt;ServiceContract&lt;/font&gt;]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;&lt;font style="background-color: #ffff00"&gt;public&lt;/font&gt;&lt;/span&gt; &lt;span &gt;interface&lt;/span&gt; IMMService&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        [&lt;font style="background-color: #ffff00"&gt;OperationContract&lt;/font&gt;]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        &lt;span &gt;void&lt;/span&gt; Max();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        [&lt;font style="background-color: #ffff00"&gt;OperationContract&lt;/font&gt;]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        &lt;span &gt;void&lt;/span&gt; Min();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;第四步，为服务添加一个Host，并且在实用实例启动时，把服务打开。&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; ServiceHost _serviceHost;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;protected&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; OnStartup(StartupEventArgs e)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            &lt;span &gt;base&lt;/span&gt;.OnStartup(e);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (isNewMutex)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;                &lt;span &gt;//1st instance of current application&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;                _serviceHost = &lt;span &gt;new&lt;/span&gt; ServiceHost(&lt;span &gt;typeof&lt;/span&gt;(MMService), &lt;span &gt;new&lt;/span&gt; Uri(&lt;span &gt;&amp;quot;net.pipe://localhost&amp;quot;&lt;/span&gt;));&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;                _serviceHost.&lt;font style="background-color: #ffff00"&gt;AddServiceEndpoint(&lt;span &gt;typeof&lt;/span&gt;(IMMService), &lt;span &gt;new&lt;/span&gt; NetNamedPipeBinding(), &lt;span &gt;&amp;quot;MMService&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                _serviceHost.Open();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            &lt;span &gt;else&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;                &lt;span &gt;// Not the 1st instance&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;                &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;关注一下第10行，其实就是定义了：C &amp;#8211; IMMService, B &amp;#8211; NetNamePipeBinding 和 A &amp;#8211; net.pipe://localhost/&lt;font style="background-color: #ffff00"&gt;MMService&lt;/font&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;地址其实是分成两部分定义的，一部分是baseAddress，是host的地址；另一部分是服务地址：MMService。&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这样，服务器端就暴露了一个叫MMService的EndPoint。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;客户端代码写在不是第一个实例中：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第一步：根据ABC，创建一个ChannelFactory对象：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;ChannelFactory&amp;lt;IMMService&amp;gt; channelFactory = &lt;span &gt;new&lt;/span&gt; ChannelFactory&amp;lt;&lt;font style="background-color: #ffff00"&gt;IMMService&lt;/font&gt;&amp;gt;(&lt;span &gt;new&lt;/span&gt; NetNamedPipeBinding(), &lt;span &gt;&amp;quot;net.pipe://localhost/MMService&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;这行代码中，&lt;strong&gt;B&lt;/strong&gt;inding和&lt;strong&gt;A&lt;/strong&gt;ddress显而易见了，&lt;strong&gt;C&lt;/strong&gt;ontract在哪儿？&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none"  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201109/20110917082848703.png" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第二步：通过CreateChannel方法，创建一个在客户端的代理类，并且调用Max/Min的方法：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;                var proxy = channelFactory.CreateChannel();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;                proxy.Max();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;这样，我们就可以F5来调试当前的应用程序了。大家会发现，如果保持现在的代码，第二次调用当前应用程序实例时，第一个实例会被最大化。&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;这跟我们预想的效果还有一点点的差距&amp;#8230;&amp;#8230;但不难解决，限于篇幅，就不再赘述了。&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;&amp;#160;&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;资源：&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;残缺版源代码（无论点击最大化还是最小化，窗口都最大化）：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;改进版二进制文件：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;（改进版中仍然有一个明显的bug哦）&lt;/p&gt;  &lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2179396.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/09/22/2179396.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/08/30/2146971.html</id><title type="text">实战Bing MAP REST服务的封装、调用</title><summary type="text">通过封装Bing地图的REST服务，来计算两地的驾驶距离。你知道从徐家汇开车到人民广场要多少路吗？:-)</summary><published>2011-08-29T21:58:00Z</published><updated>2011-08-29T21:58:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/30/2146971.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/30/2146971.html"/><content type="html">&lt;p&gt;什么是REST服务？&lt;/p&gt;  &lt;p&gt;如果您不知道答案，那么，请您花&lt;strong&gt;5分钟时间&lt;/strong&gt;来浏览一下这个教程：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://rest.elkstein.org/"&gt;Learn REST: A Tutorial&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;(&lt;em&gt;就5分钟，您就读一下吧。)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108201027449877.png"&gt;&lt;img style="border-width: 0px; margin: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108201027527590.png" width="556" height="662" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;(图片来自Bing搜索)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;您已经知道了，由于REST是基于HTTP协议的服务，它有以下&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;  &lt;ul&gt;&lt;li&gt;平台无关&amp;#8212;&amp;#8212;例如用Unix架的服务器提供的服务，可以在PC、MAC等其它终端，甚至手机上调用； &lt;/li&gt;&lt;li&gt;语言无关&amp;#8212;&amp;#8212;C#架的服务，可以被Java甚至JavaScript调用； &lt;/li&gt;&lt;li&gt;便于跨防火墙存取数据； &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;接下来，用一个例子，来说明怎么设计一组类（三个），用来&lt;strong&gt;封装&lt;/strong&gt;并&lt;strong&gt;调用REST服务&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;em&gt;（如果你想知道用.NET怎么创建REST服务？请花30分钟左右看看：&lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/dd315413.aspx" target="_blank"&gt;&lt;em&gt;An Introduction To RESTful Services With WCF&lt;/em&gt;&lt;/a&gt;&lt;em&gt;）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;任务：&lt;/strong&gt;封装Bing地图的REST服务，来计算一个两地的驾驶距离。（&lt;em&gt;你知道从徐家汇开车到人民广场要多少路吗？ &lt;img style=""  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108290411503729.png" /&gt;&lt;/em&gt;）&lt;/p&gt;  &lt;p&gt;要调用一个REST服务，要知道两个要素：&lt;/p&gt;  &lt;ul&gt;&lt;li&gt;URL模板&amp;#8212;&amp;#8212;发送请求的字符串的格式； &lt;/li&gt;&lt;li&gt;XML响应&amp;#8212;&amp;#8212;用XML表达的返回的结果； &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Bing Map的&lt;strong&gt;URL模板&lt;/strong&gt;如下(&lt;a href="http://msdn.microsoft.com/en-us/library/ff701717.aspx" target="_blank"&gt;来源于MSDN&lt;/a&gt;)：&lt;/p&gt;  &lt;pre &gt;http://dev.virtualearth.net/REST/v1/Routes/travelMode?wayPoint.1=wayPoint1&amp;amp;heading=heading&amp;amp;waypoint.2=wayPoint2&amp;amp;wayPoint.n=wayPointn&lt;/pre&gt;&#xD;
&#xD;
&lt;pre &gt;&amp;amp;optimize=optimize&amp;amp;avoid=avoidOptions&amp;amp;distanceBeforeFirstTurn=distanceBeforeFirstTurn&amp;amp;timeType=timeType&amp;amp;dateTime=dateTime&amp;amp;maxSolutions=maxSolutions&lt;/pre&gt;&#xD;
&#xD;
&lt;pre &gt;&amp;amp;routePathOutput=routePathOutput&amp;amp;tolerances=tolerance1,tolerance2,tolerancen&amp;amp;distanceUnit=distanceUnit&amp;amp;key=BingMapsKey&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;-.-||好长的字符串啊。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;对应的&lt;strong&gt;XML响应&lt;/strong&gt;就不&amp;#8220;如下&amp;#8221;了，大家根据需要看&lt;a href="http://msdn.microsoft.com/en-us/library/ff701718.aspx" target="_blank"&gt;MSDN&lt;/a&gt;吧。为了便于直观理解，MSDN同时提供了一些&lt;a href="http://msdn.microsoft.com/en-us/library/gg636955.aspx" target="_blank"&gt;例子&lt;/a&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;另外，对于Bing地图的开发，还需要有一个对应的应用程序Key，这个Key用于识别调用Bing地图服务的应用程序。大家可以在这儿&lt;a href="https://www.bingmapsportal.com/" target="_blank"&gt;免费申请和查看开发者KEY&lt;/a&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;我的Key是：我不告诉你。您就&lt;/em&gt;&lt;a href="https://www.bingmapsportal.com/" target="_blank"&gt;&lt;em&gt;自己申请一个吧&lt;/em&gt;&lt;/a&gt;&lt;em&gt;。&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这样，准备就做得差不多了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;既然是实战，达成目标优先，因此，设计一个类来达成目标。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这个类得有一个方法可以计算距离：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;它的返回值是一个double类型； &lt;/li&gt;&lt;li&gt;它需要根据参数来计算距离，最直观的参数就是URL； &lt;/li&gt;&lt;li&gt;我们可以用WebClient来触发一个进行一个Http请求； &lt;/li&gt;&lt;li&gt;返回的结果是HTML，因此，我们LinqToXml来进行处理； &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;所以，就有了如下的代码：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.Net;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&lt;span &gt;using&lt;/span&gt; System.Xml.Linq;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;&lt;span &gt;namespace&lt;/span&gt; BingMapRouteDistanceDemo&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; RouteDistanceCalculator&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;double&lt;/span&gt; GetDistance(&lt;span &gt;string&lt;/span&gt; requestUrl)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            WebClient client = &lt;span &gt;new&lt;/span&gt; WebClient();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            &lt;span &gt;string&lt;/span&gt; resultXML = client.DownloadString(requestUrl);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            XElement xml = XElement.Parse(resultXML);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;            &lt;span &gt;string&lt;/span&gt; resultString = xml.Descendants(&lt;span &gt;"TravelDistance"&lt;/span&gt;).First().Value;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; Convert.ToDouble(resultString);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;嗯，您是不是已经准备拍砖了？&lt;img style=""  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920373780.png" /&gt;&amp;nbsp;&lt;em&gt;（千万冷静，除非您正想换显示器愁没借口&amp;#8230;&amp;#8230;）&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;至少，这个类&lt;strong&gt;基本上&lt;/strong&gt;能够正常用（其实是用不起来的）。如果把这样一个类应用到项目中，会有哪些问题？&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;您一定已经看出来了，至少有两个明显的问题&lt;em&gt;（欢迎补充）&lt;/em&gt;：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;输入参数&lt;/strong&gt;是一个字符串&amp;#8212;&amp;#8212;而且是一个长长的字符串 &#xD;
&#xD;
    &lt;ul&gt;&lt;li&gt;构建这个字符串的任务交给用户，效率低，函数难用且极易出错； &lt;/li&gt;&lt;li&gt;这么一串长长的字符串中出了错，你也不知道到底哪儿错了，得一个一个排查。 &lt;/li&gt;&#xD;
    &lt;/ul&gt;&#xD;
  &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;让我们看看，如果要调用这个类，大概的代码是什么样子的：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;            RouteDistanceCalculator route = &lt;span &gt;new&lt;/span&gt; RouteDistanceCalculator();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;            Console.WriteLine(&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;                route.GetDistance(&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;                &lt;span &gt;@"http://dev.virtualearth.net/REST/V1/Routes?wp.0=37.779160067439079,-122.42004945874214&amp;amp;wp.1=32.715685218572617,-117.16172486543655&amp;amp;key=BingMapsKey"&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;                );&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;如果您熟悉数据库编程，想想手动编写数据库连接字符串的感觉就有体会了。&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;当前类既处理输入（URL），还处理输出（XML），不符合单一责任原则&amp;#8212;&amp;#8212;不解释&lt;img style=""  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920373780.png" /&gt;； &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;在封装REST服务时，这两个问题也较普遍。我们分别来解决它们。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920394487.jpg"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="3d_wallpaper_gallery20290" border="0" alt="3d_wallpaper_gallery20290" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920404006.jpg" width="660" height="380" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;(图片来自Bing搜索)&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先，我们可以&lt;strong&gt;构建一个专门用于创建URL请求的类&lt;/strong&gt;，这个类有以下特征：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;把提供给用户输入的每一个参数对应于一个属性；参数的值对应于属性的值； &lt;/li&gt;&lt;li&gt;暴露一个方法，用于返回最终的URL； &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;示意代码如下，文后附完整项目。&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;div &gt;&#xD;
    &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; RouteDistanceCalculator&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;// Pay attention to change of the parameter type.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;double&lt;/span&gt; GetDistance(RouteRequestBuilder requestBuilder)&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            WebClient client = &lt;span &gt;new&lt;/span&gt; WebClient();&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            &lt;span &gt;// Builder have the responsibility of forming query string.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            &lt;span &gt;string&lt;/span&gt; resultXML = client.DownloadString(requestBuilder.GetQueryString());&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;...&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; RouteRequestBuilder&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Public Method&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        &lt;span &gt;/// Go over properties one by another to construct the query uri.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;virtual&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; GetQueryString()&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;            StringBuilder resultBuilder = &lt;span &gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;            resultBuilder.Append(BasicQueryUri);&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;            &lt;span &gt;// Construct for travel mode&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;            resultBuilder.AppendFormat(&lt;span &gt;"{0}?"&lt;/span&gt;, TravelMode.ToString());&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;            &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; resultBuilder.ToString();&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Query conditions&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IList&amp;lt;Location&amp;gt; WayPoints { get; set; }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TravelMode TravelMode { get; set; }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  33:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TransitTimeType TravelTimeType { get; set; }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; DateTime TravelDateTime { get; set; }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;  35:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
  &lt;/div&gt;&#xD;
  &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;RouteRequestBuilder就是这么一个前文描述的类。其分为两大部分，15到28行Public Method&lt;strong&gt;暴露了一返回URL的方法&lt;/strong&gt;GetQueryString；而30到35行的Query Conditions把需要用户输入的&lt;strong&gt;查询条件&lt;/strong&gt;做成的属性。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;这样，用户就只要创建对象并给它的属性赋值，再不用担心构建字符串的问题了。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;接下来，看输出结果。XML是REST服务输出的普遍形式。如果像文中一样，直接处理XML，一旦返回的XML格式调整或者扩展，我们需要一个方法一个方法的修改。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;假如我们要多个结果，并且结果还被多处调用，那么，对于项目来说，结果是灾难性的。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;所以，您已经想到了，可以&lt;strong&gt;把处理结果的逻辑封装起来形成一个类&lt;/strong&gt;，这个类有如下特征：&lt;/div&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;&#xD;
    &lt;div &gt;有一个方法或者属性，可以获取到原始的结果&amp;#8212;&amp;#8212;例子中webClient返回的XML；&lt;/div&gt;&#xD;
  &lt;/li&gt;&lt;li&gt;&#xD;
    &lt;div &gt;把用户关心的内容，以属性的形式暴露出来；&lt;/div&gt;&#xD;
  &lt;/li&gt;&lt;li&gt;&#xD;
    &lt;div &gt;用户无须知道XML与属性值的对应关系；&lt;/div&gt;&#xD;
  &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p &gt;由于用户不需要知道XML的细节，因此，对于这个类来说，如果把结果保存到ResultString属性中，我们不需要暴露它的读方法，意味着这是一个&lt;strong&gt;&amp;#8220;只写&amp;#8221;属性&lt;/strong&gt;，那么，我们就可以把它&lt;strong&gt;做成一个方法&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p &gt;在这里，我们只关心行驶距离，因此，它应该有一个叫Distance的属性，返回一个double类型的值。&lt;/p&gt;&#xD;
&#xD;
&lt;p &gt;形成的类主要代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; RouteResponseResolver&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Properties&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;/// Get distance of the route.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;double&lt;/span&gt; Distance&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            get&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                &lt;span &gt;return&lt;/span&gt; GetDistance();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Private Methods&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;span &gt;double&lt;/span&gt; GetDistance()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;            &lt;span &gt;// Covert xml into property&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Public Methods&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;        &lt;span &gt;/// Update the result string to resolve with&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;        &lt;span &gt;/// &amp;lt;param name="resultString"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; UpdateResultString(&lt;span &gt;string&lt;/span&gt; resultString)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;            &lt;span &gt;// Update result string&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  33:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;对应的，我们就需要修改一下RouteDistanceCalculator类，把RouteResponseResolver也作为一个参数传入：&lt;/font&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; RouteDistanceCalculator&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;double&lt;/span&gt; GetDistance(RouteRequestBuilder requestBuilder, RouteResponseResolver resultResolver)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            WebClient client = &lt;span &gt;new&lt;/span&gt; WebClient();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;string&lt;/span&gt; resultXML = client.DownloadString(requestBuilder.GetQueryString());&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            resultResolver.UpdateResultString(resultXML);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; resultResolver.Distance;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;费了这么多神，我们得到了什么？让我们再来看一下，现在的用户如何来调用RouteDistanceCalculator.&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;static&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; Main(&lt;span &gt;string&lt;/span&gt;[] args)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            RouteDistanceCalculator route = &lt;span &gt;new&lt;/span&gt; RouteDistanceCalculator();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            RouteRequestBuilder requestBuilder = &lt;span &gt;new&lt;/span&gt; RouteRequestBuilder()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                TravelMode = TravelMode.Driving,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;                WayPoints = &lt;span &gt;new&lt;/span&gt; List&amp;lt;Location&amp;gt;()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;                    &lt;span &gt;// Location for Xujiahui, Shanghai&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;                    &lt;span &gt;new&lt;/span&gt; Location(){ Latitude=31.1970231682062, Longitude=121.441092118621},&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                    &lt;span &gt;// Location for people's square&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;                    &lt;span &gt;new&lt;/span&gt; Location(){ Latitude=31.233944, Longitude=121.467813}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            };&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;            RouteResponseResolver responseResolver = &lt;span &gt;new&lt;/span&gt; RouteResponseResolver();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;            var distance = route.GetDistance(requestBuilder, responseResolver);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;            Console.WriteLine(&lt;span &gt;"Drive distance between Xujiahui &amp;amp; People's square are: {0} km."&lt;/span&gt;, distance);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;可以看到，通过RouteRequestBuilder类，我们指定了路径类型为驾程，一共涉及到两个点，分别是徐家汇和人民广场；我们用responseResolver来解析查询到的结果&amp;#8230;&amp;#8230;&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;由于请求不再要求用户输入字符串，出错机率减小，即使出错，调试也相对容易许多； &lt;/li&gt;&lt;li&gt;对于RouteDistanceCalculator来说，请求和响应解析的类是可以被替换的； &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;最后，揭晓徐家汇到人民广场的车程：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920421333.gif"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="Garfield-drives-a-car" border="0" alt="Garfield-drives-a-car" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920438169.gif" width="260" height="178" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;(图片来自Bing搜索)&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920441068.png"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="DistanceFromXujiahuiToPeoplesSquare" border="0" alt="DistanceFromXujiahuiToPeoplesSquare" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108230920454317.png" width="681" height="130" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;最后的后面：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;下一步&amp;#8230;&amp;#8230;在这里的请求生成和响应解析类都是具体类，如果&lt;strong&gt;把它们抽象成接口&lt;/strong&gt;，会&lt;strong&gt;进一步降低它们之间的耦合性&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;小结一下：&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;一个REST服务总可以封装成三个类：&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&lt;li&gt;调用类&amp;#8212;&amp;#8212;调用以下两个类； &lt;/li&gt;&lt;li&gt;请求生成类&amp;#8212;&amp;#8212;以属性形式接受查询条件的输入，提供生成请求URL的方法； &lt;/li&gt;&lt;li&gt;响应解析类&amp;#8212;&amp;#8212;用于解析返回的结果，以属性返回用户感兴趣的数据； &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;p&gt;如果将后两个类抽象成对应接口，即可实现请求、响应与调用类之间的解耦合。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;资源：&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://rest.elkstein.org/"&gt;Learn REST: A Tutorial&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/dd315413.aspx" target="_blank"&gt;&lt;em&gt;An Introduction To RESTful Services With WCF&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="https://www.bingmapsportal.com/" target="_blank"&gt;Bing Map开发中心&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd877180.aspx" target="_blank"&gt;Bing Map SDK&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;示例代码：为了方便大家看上下类的关系，我把所有的类全放在一个文件里了，一般不推荐这样做；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;另外，使用示例前，请把文件底部的BingMapKey换成您自己的Key。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt; &#xD;
  &lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2146971.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/30/2146971.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/08/15/2133208.html</id><title type="text">选好 Async 函数的返回类型</title><summary type="text">一个异步方法的返回值有三个选项：void, Task, Task`1。 什么时候使用哪一种返回类型，是有讲究的。一不小心使用不当，会让代码产生意想不到的结果。为了避免在将同步代码改成异步代码时出现返回类型选择不恰当的情况，给大家介绍ASync选择返回类型的三法则...</summary><published>2011-08-15T02:13:00Z</published><updated>2011-08-15T02:13:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/15/2133208.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/15/2133208.html"/><content type="html">&lt;p&gt;在&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/06/27/AsyncDemo.html" target="_blank"&gt;C# 5.0功能之Async一瞥&lt;/a&gt;中，简单的介绍了Async CTP的使用，我们一起领略了下一版本的C#可能给我们带来的强大而简单的编写异步执行的代码的方法。&lt;/p&gt;  &lt;p&gt;文中提到一个异步方法的&lt;strong&gt;返回值&lt;/strong&gt;有三个选项：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;void &lt;/li&gt;    &lt;li&gt;Task &lt;/li&gt;    &lt;li&gt;Task&amp;lt;T&amp;gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;什么时候使用哪一种返回类型，是有讲究的。一不小心使用不当，会让代码产生意想不到的结果。为了避免在将同步代码改成异步代码时出现返回类型选择不恰当的情况，给大家介绍ASync选择返回类型的&lt;strong&gt;三法则&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810022394.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810077721.png" border="0" height="542" width="455" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;（图片来自Bing搜索）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;（还是申明一下：本文的例子基于Async CTP SP1 Refresh完成。由于 Async还处于CTP阶段，很多东西还在讨论，因此，也许到正式发布的时候，细节还会变动。）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;假设有一个学生类，包括&lt;strong&gt;学号ID&lt;/strong&gt;和&lt;strong&gt;姓名Name&lt;/strong&gt;属性：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; Student&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; ID { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; ToString()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; &lt;span &gt;string&lt;/span&gt;.Format(&lt;span &gt;"ID: {0}, Name: {1}."&lt;/span&gt;, ID, Name);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;然后，有一组学生记录的StudentRepository：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;div &gt;&#xD;
    &lt;div &gt;&#xD;
      &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; StudentRepository&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        ICollection&amp;lt;Student&amp;gt; storage;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; ICollection&amp;lt;Student&amp;gt; GetStudents()&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            var studentCollection = CreateStudents();&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            UpdateNameUnknownStudent(studentCollection);&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; studentCollection;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; ICollection&amp;lt;Student&amp;gt; CreateStudents()&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            Thread.Sleep(2000);&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;            storage = &lt;span &gt;new&lt;/span&gt; Collection&amp;lt;Student&amp;gt;()&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;                &lt;span &gt;new&lt;/span&gt; Student(){ ID=1 },&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;                &lt;span &gt;new&lt;/span&gt; Student(){ ID=2 }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;            };&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; storage;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; UpdateNameUnknownStudent(ICollection&amp;lt;Student&amp;gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;                Thread.Sleep(1000); &lt;span &gt;// Someoperation time like db access or so.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;                student.Name = student.Name ?? &lt;span &gt;"Unknown"&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
    &lt;/div&gt;&#xD;
    &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
  &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;其中，12行的CreateStudents方法&lt;strong&gt;模拟了学生对象的创建&lt;/strong&gt;，它返回一个学生集合；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第23行UpdateNameUnkownStudent方法遍历学生集合，并且，&lt;strong&gt;如果学生的姓名为空，将学生姓名设置成&amp;#8220;Unknown&amp;#8221;&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第5行GetStudents()作为公开的接口，&lt;strong&gt;先后调用CreateStudnets和UpdateNameUnknownStudent方法&lt;/strong&gt;，并将结果返回。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;为了模拟现实代码中例如数据库等操作的处理时间，在第14行和第27行分别加了延时。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;然后，创建一个WPF UI，调用上面的StudentRepository类，把结果存放到一个Label中。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;界面如下：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810088179.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810088636.png" border="0" height="379" width="561" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Demo按钮的事件处理代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; btnDemo_Click(&lt;span &gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            StudentRepository repository = &lt;span &gt;new&lt;/span&gt; StudentRepository();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            var studentCollection = repository.GetStudents();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            StringBuilder builder = &lt;span &gt;new&lt;/span&gt; StringBuilder(studentCollection.Count);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;                builder.AppendLine(student.ToString());&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            lblResult.Content = builder.ToString();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;执行代码，虽然代码能够得到正确结果，但是，在点击Demo按钮后，&lt;strong&gt;界面出现了几秒钟的死锁&lt;/strong&gt;。为了提供更好的用户体验，我们决定把学生创建和为空名学生记录添加Unknown的方法&lt;strong&gt;改写成异步&lt;/strong&gt;方法。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108110131082262.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108110131187650.png" border="0" height="576" width="483" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;（图片来自Bing搜索）&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先看CreateStudents方法，它返回一个ICollection&amp;lt;Student&amp;gt;的集合。&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;&lt;font size="4"&gt;&lt;font size="2"&gt;法则一：对于&lt;/font&gt;&lt;u&gt;&lt;strong&gt;需要返回对象的方法&lt;/strong&gt;，我们添加async关键字后，&lt;strong&gt;改为返回Task&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/u&gt;&lt;/font&gt;，也即，改为： &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; async &lt;strong&gt;Task&amp;lt;ICollection&amp;lt;Student&amp;gt;&amp;gt;&lt;/strong&gt; CreateStudentsAsync()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            await TaskEx.Delay(2000);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            storage = &lt;span &gt;new&lt;/span&gt; Collection&amp;lt;Student&amp;gt;()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                &lt;span &gt;new&lt;/span&gt; Student(){ ID=1 },&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;                &lt;span &gt;new&lt;/span&gt; Student(){ ID=2 }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            };&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; storage;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;接下来，我们看UpdateNameUnknownStudent方法，由于它不返回结果，我们直接加上async：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;div &gt;&#xD;
    &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;div &gt;&#xD;
      &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;strong&gt;async &lt;span &gt;void&lt;/span&gt;&lt;/strong&gt; UpdateNameUnknownStudentAsync(ICollection&amp;lt;Student&amp;gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;                await TaskEx.Delay(1000); &lt;span &gt;// Someoperation time like db access or so.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                student.Name = student.Name ?? &lt;span &gt;"Unknown"&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
      &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
    &lt;/div&gt;&#xD;
    &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
  &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;相应的GetStudent方法和Demo按钮也加上async关键字和await等待结果后，重新编译运行。点击Demo按钮。我们发现，&lt;strong&gt;界面是不死锁了，但是结果出错了&lt;/strong&gt;（就说会产生意想不到的结果吧）：&lt;/p&gt;&#xD;
&#xD;
&lt;table border="0" cellpadding="2" cellspacing="0" width="400"&gt;&lt;tbody&gt;&#xD;
    &lt;tr&gt;&#xD;
      &lt;td valign="top" width="400"&gt;ID: 1, Name: . &#xD;
        &lt;br /&gt;ID: 2, Name: .&lt;/td&gt;&#xD;
    &lt;/tr&gt;&#xD;
  &lt;/tbody&gt;&lt;/table&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;显然，UpdateNameUnknownStudentAsync没有运行。让我们来仔细的看一下&lt;strong&gt;执行流&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先，Demo按钮Click事件调用者调用GetStudentAsync，&lt;strong&gt;为理清调用层次&lt;/strong&gt;，我们记btnDemo_Click方法为&lt;strong&gt;L1方法&lt;/strong&gt;：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; async &lt;span &gt;void&lt;/span&gt; btnDemo_Click(&lt;span &gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            StudentRepository repository = &lt;span &gt;new&lt;/span&gt; StudentRepository();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            var studentCollection = &lt;strong&gt;await&lt;/strong&gt; repository.GetStudentsAsync();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            StringBuilder builder = &lt;span &gt;new&lt;/span&gt; StringBuilder(studentCollection.Count);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;                builder.AppendLine(student.ToString());&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            lblResult.Content = builder.ToString();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;当执行到第4行时，&lt;strong&gt;遇到await关键字&lt;/strong&gt;，调用GetStudentsAsync方法（记为&lt;strong&gt;L2方法&lt;/strong&gt;），并且进入等待状态，&lt;strong&gt;等待L2结果&lt;/strong&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;GetStudentAsync(L2)此时代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; async Task&amp;lt;ICollection&amp;lt;Student&amp;gt;&amp;gt; GetStudentsAsync()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            var studentCollection = &lt;strong&gt;await&lt;/strong&gt; CreateStudentsAsync();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            UpdateNameUnknownStudentAsync(studentCollection); &lt;font color="#008000"&gt;// We have a problem here &amp;#8230;&lt;/font&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; studentCollection;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;当它执行第3行代码，调用CreateStudnetsAsync以后，遇到await关键字，等待CreateStudentAsync的完成。&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;CretaeStudent方法完成后，L2方法继续执行到调用UpdateNameUnknownStudentAsync方法（记为&lt;strong&gt;L3方法&lt;/strong&gt;）：&lt;/pre&gt;&#xD;
&#xD;
  &lt;div &gt;&#xD;
    &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; async &lt;span &gt;void&lt;/span&gt; UpdateNameUnknownStudentAsync(ICollection&amp;lt;Student&amp;gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;                await TaskEx.Delay(1000); &lt;span &gt;// Someoperation time like db access or so.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                student.Name = student.Name ?? &lt;span &gt;"Unknown"&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
    &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
  &lt;/div&gt;&#xD;
  &lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;L3执行到第5行时，遇到了await，当前线程开始等待TaskEx.Delay完成；&lt;strong&gt;同时，它会检查它的调用者（L2）是否有代码可以在当前线程上执行&lt;/strong&gt;。由于在L2中，并&lt;strong&gt;没有await L3&lt;/strong&gt;方法，因此，当L3中await一个结果时，L2所在进程会执行下一个语句：return studentCollection。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;L1中的await等到了L2的return，进而进行下一语句&amp;#8230;&amp;#8230;然而，此时此刻，添加Unknown的M3其实还没有完成。前面看到的残缺的结果就这样被显示了出来。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;引入这个问题的&lt;strong&gt;原因&lt;/strong&gt;是，由于在有async关键字的情况下，void或者返回Task都不需要在代码中显式的使用return，我们在改写UpdateNameStudentAsync方法时，&lt;strong&gt;没有仔细考虑应当使用void还是Task作为返回类型&lt;/strong&gt;。因此，到底是返回Task还是保持void是一个在刚开始使用Async时经常遇到的问题。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;明白了代码执行流以后，判断方法就不难了：&lt;/div&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
  &lt;li&gt;&#xD;
    &lt;div &gt;法则二、当一个方法属于&lt;font size="4"&gt;&lt;u&gt;&lt;strong&gt;触发后不用理会什么时候完成的方法&lt;/strong&gt;，可以直接使用void&lt;/u&gt;，&lt;/font&gt;例如事件处理函数(Event Handler)；&lt;/div&gt;&#xD;
  &lt;/li&gt;&#xD;
&#xD;
  &lt;li&gt;&#xD;
    &lt;div &gt;&lt;font size="4"&gt;&lt;font size="2"&gt;法则三、当&lt;/font&gt;&lt;u&gt;虽然不需要返回结果，但却&lt;strong&gt;需要知道是否执行完成&lt;/strong&gt;的方法时，返回一个Task&lt;/u&gt;&lt;/font&gt;，例如示例中的UpdateNameUnknownStudnetAsync方法。&lt;/div&gt;&#xD;
  &lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;在把示例中UpdateNameUnknownStudentAsync方法改成如下形式，并且在GetStudentAsync方法中await它以后，我们便可以得到预期的结果了：&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; async &lt;strong&gt;&lt;font color="#ff0000"&gt;Task&lt;/font&gt;&lt;/strong&gt; UpdateNameUnknownStudentAsync(ICollection&amp;lt;Student&amp;gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var student &lt;span &gt;in&lt;/span&gt; studentCollection)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;                await TaskEx.Delay(1000); &lt;span &gt;// Someoperation time like db access or so.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                student.Name = student.Name ?? &lt;span &gt;"Unknown"&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810108504.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201108/201108100810116420.png" border="0" height="354" width="529" /&gt;&lt;/a&gt;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;写在最后&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;Async/await的引入虽然为提供了我们书写异步执行代码的捷径，但是，要用好这把双刃剑，得在&lt;strong&gt;理解Async代码的执行流程&lt;/strong&gt;的基础上&lt;strong&gt;不断总结&lt;/strong&gt;、&lt;strong&gt;多练多用&lt;/strong&gt;啊。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;font size="3"&gt;资源下载：&lt;/font&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;* Sync 版源代码&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;* Async 版源代码&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;* &lt;a href="http://msdn.com/async" target="_blank"&gt;Async CTP SP1 Refresh&lt;/a&gt;.&lt;/p&gt; &lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2133208.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/08/15/2133208.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/07/30/2120626.html</id><title type="text">用WCF + Entity Framework 序列化时的陷阱</title><summary type="text">当使用WCF + Entity Framework时要小心，否则，很容易掉入各种陷阱。这里介绍两个在序列化时容易遇到的、会导致服务停止的陷阱。一、试图序列化Entity Proxy类而导致服务停止；二、序列化时出现死循环导致服务停止；首先要透过假象，看到问题的本质，具体分析问题的特殊性，结合经验，来查找问题...</summary><published>2011-07-29T18:06:00Z</published><updated>2011-07-29T18:06:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/30/2120626.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/30/2120626.html"/><content type="html">&lt;p&gt;&lt;font size="2"&gt;当使用WCF + Entity Framework时要小心，否则，&lt;strong&gt;很容易&lt;/strong&gt;掉入各种陷阱。这里介绍两个在序列化时容易遇到的、会导致&lt;strong&gt;服务停止&lt;/strong&gt;的陷阱。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;一、试图序列化Entity Proxy类而导致服务停止。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;二、序列化时出现死循环导致服务停止；&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;无论掉入哪一个陷阱，在&lt;strong&gt;客户端&lt;/strong&gt;都会看到这样的对话框(点击看大图)：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107300142552200.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/20110730014257365.png" border="0" height="180" width="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;呃~这个图才对&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none"  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107300142586330.png" /&gt;：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107290947264061.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107290947291255.png" border="0" height="398" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;大致意思是会说：服务不在线或者客户端配置有问题或者Proxy类有问题。而如果跟着Error Details里的第一行Google，会找到许多文章关于调整数据缓存大小、调整操作超时时间&amp;#8230;&amp;#8230;如果按照常规则调试方法&amp;#8212;&amp;#8212;按图索骥找问题，那么就可能越陷越深。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;查找问题时，首先要&lt;strong&gt;透过假象&lt;/strong&gt;，看到问题的&lt;font size="2"&gt;&lt;strong&gt;本质&lt;/strong&gt;&amp;#8212;&amp;#8212;WCF服务因为某些原因而停止了。其次，我们要具体分析问题的&lt;strong&gt;特殊性&lt;/strong&gt;，结合经验，来查找问题。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;服务停止有一个典型的原因，那就是&lt;strong&gt;序列化出问题了&lt;/strong&gt;。由于在WCF中，序列化不需要我们写代码实现，它在为我们提供便利的同时，也埋下了伏笔。而EF的使用，又进一步将事情变得错综复杂。凡事有弊有利，往往是使用了EF这样的&lt;strong&gt;特殊性&lt;/strong&gt;，让我们查找问题时也更具方向性。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;EF中，有什么特性会与WCF交互？没错，&lt;strong&gt;我们常常把EF的实体类用作DataContract&lt;/strong&gt;。&lt;/font&gt;&lt;font size="2"&gt;EF的实体类，无论是生成的还是通过Code First写的，运行时，为了支持EF的一些&amp;#8220;高级&amp;#8221;功能，例如，LazyLoad，Runtime会从你的Entity类&lt;strong&gt;自动继承出一个对应的代理类(Proxy Types)&lt;/strong&gt;并对代理类对象进行操作。例如Person类，在运行时或者就会对应有一个叫Person123456类（肯定不会叫这个名字啦，这权当标识一下）。我们写代码时对Person的操作，运行时会换成对Person123456的操作。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;通过调试窗口，我们可以到看到这个隐藏在背后的类（代码类为Handbook，实际类为DynamicProxies.Handbook_AE28&amp;#8230;84）：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107290947317502.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107290947334207.png" border="0" height="210" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;这样一来，WCF，具体的说，是DataContractSerializer就不认账了&amp;#8212;&amp;#8212;&lt;strong&gt;我只认识老子（Handbook），不认识儿子（代理类），没法序列化&lt;/strong&gt;！于是它抛出了异常，导致&lt;strong&gt;服务中断&lt;/strong&gt;。这样一来，我们会看到，用WCF返回一般的对象没有问题，一旦返回实体类对象，就会遇到了文章开始时看到的错误。&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;一个简单的解决方法：让DbContext使用静态类。在对应的DbContext的构造函数里添加一个设置即可：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MTBContainer : DbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; MTBContainer()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            : &lt;span &gt;base&lt;/span&gt;(&lt;span &gt;"name=MTBContainer"&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;span &gt;this&lt;/span&gt;.Configuration.ProxyCreationEnabled = &lt;span &gt;false&lt;/span&gt;; &lt;span &gt;&lt;font style="background-color: #ffff00"&gt;// This is the line added.&lt;/font&gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;//...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IDbSet&amp;lt;PlacePictureType&amp;gt; PlacePictureTypes { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;//...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第二个容易遇到的问题是序列化死循环的问题。乍一看错误跟第一个显示的是一样的：&lt;strong&gt;服务不可用&lt;/strong&gt;了！而且同样是序列化问题。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;但是，这类问题有一个&lt;strong&gt;特别的地方&lt;/strong&gt;：有些实体类对象能正常返回，有些不能。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;经过观察分析发现，不能返回的类往往是那些有Navigation属性的实体类，进一步分析，Navigation属性往往会&lt;strong&gt;构成对自身的间接引用&lt;/strong&gt;：例如在一对多表里，往往一端有一个多端对象的集合，同时，多端又有一个一端的引用。比如有一个Parent实体，有一个Child实体，那么，Parent里会有一个ICollection&amp;lt;Child&amp;gt;用来存储所有的孩子，而Child里又会有一个Parent用来指明当前这个Child的Parent。这种互相引用的关系导致了DataContractSerializer在&lt;strong&gt;序列化&lt;/strong&gt;它时出现了问题。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;看来，不光光是在EF中会遇到这样的问题，DataContractSerializer序列化一个&lt;strong&gt;直接或者间接引用了自己的类对象&lt;/strong&gt;，就会陷入死循环。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;em&gt;说话&amp;#8230;&amp;#8230;Visual Studio的图标是不是像一个死循环？^v^&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107300143003656.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107300143019936.png" border="0" height="139" width="244" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;回正题，以上面描述的类为例：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;//[DataContract(IsReference = true)]&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    [DataContract]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; Parent&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; Parent()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            Children = &lt;span &gt;new&lt;/span&gt; List&amp;lt;Child&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        [DataMember]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        [DataMember]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IList&amp;lt;Child&amp;gt; Children { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;    &lt;span &gt;//[DataContract(IsReference = true)]&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    [DataContract]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; Child&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;        [DataMember]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;        [DataMember]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; Parent ParentRef { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;我们在Console Applicatin的Main函数里试着用DataContractSerializer序列化它：&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;            &lt;span &gt;// Create mock objects&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;            Parent p = &lt;span &gt;new&lt;/span&gt; Parent() { Name = &lt;span &gt;"Baba"&lt;/span&gt; };&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            Child c1 = &lt;span &gt;new&lt;/span&gt; Child() { Name = &lt;span &gt;"John"&lt;/span&gt;, ParentRef = p };&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            Child c2 = &lt;span &gt;new&lt;/span&gt; Child() { Name = &lt;span &gt;"Alice"&lt;/span&gt;, ParentRef = p };&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            p.Children.Add(c1);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            p.Children.Add(c2);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;           &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;           &lt;span &gt;// Creat DataContractSerializer&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            DataContractSerializer serializer = &lt;span &gt;new&lt;/span&gt; DataContractSerializer(&lt;span &gt;typeof&lt;/span&gt;(Parent));&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;           &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;            &lt;span &gt;// Serialize &amp;amp; output results.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            &lt;span &gt;string&lt;/span&gt; result = &lt;span &gt;null&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            &lt;span &gt;using&lt;/span&gt; (Stream s = &lt;span &gt;new&lt;/span&gt; MemoryStream())&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;                serializer.WriteObject(s, p);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;                s.Seek(0, SeekOrigin.Begin);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;                &lt;span &gt;using&lt;/span&gt; (StreamReader r = &lt;span &gt;new&lt;/span&gt; StreamReader(s))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;                    result = r.ReadToEnd();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;            Console.WriteLine(result);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;运行结果是：Crash。&lt;strong&gt;默认情况下&lt;/strong&gt;，DataContractSerializer是这么&lt;strong&gt;把对象层层展开&lt;/strong&gt;：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Parent&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;   &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Children&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;       &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Child&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;           &lt;strong&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Parent&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/strong&gt;    &lt;span &gt;&amp;lt;!&amp;#8212;- this is Child.Parent Property&amp;#8230; Enter into endless loop --&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;               &lt;strong&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Children&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/strong&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;它不会顾及引用关系，只会一味的把对象的属性展成对应的XML元素。因此，Parent &amp;#8211;&amp;gt; Child1 &amp;#8211;&amp;gt; Parent &amp;#8211;&amp;gt; Child1&amp;#8230;&lt;strong&gt;无穷匮也&lt;/strong&gt;了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;解决方法一、已经在上面的代码里了：在DataContract上使用IsReference参数，并且设置为true。（[DataContract(&lt;strong&gt;IsReference = true&lt;/strong&gt;)]）。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;解决方法二、调用&lt;strong&gt;DataContractSerializer&lt;/strong&gt;的另一个&lt;strong&gt;构造函数&lt;/strong&gt;来替代上面代码中的第9行：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;DataContractSerializer serializer = &lt;span &gt;new&lt;/span&gt; DataContractSerializer(&lt;span &gt;typeof&lt;/span&gt;(Parent),&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;"Parent"&lt;/span&gt;,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;string&lt;/span&gt;.Empty,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;null&lt;/span&gt;,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt;.MaxValue,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;false&lt;/span&gt;,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        &lt;span &gt;true&lt;/span&gt;,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;null&lt;/span&gt;,&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        &lt;span &gt;null&lt;/span&gt;);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;第7行用来表明使用Preserve Object Reference。使用了Preserve Object Reference以后，会产生类似以下代码的序列化结果，&lt;strong&gt;每个元素都会有其对应的Id，对象引用对引用Id&lt;/strong&gt;：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Parent&lt;/span&gt; &lt;span &gt;z:Id&lt;/span&gt;&lt;span &gt;="i1"&lt;/span&gt; &lt;span &gt;xmlns&lt;/span&gt;&lt;span &gt;="http://schemas.datacontract.org/2004/07/Sealize"&lt;/span&gt; &lt;span &gt;xmlns:i&lt;/span&gt;&lt;span &gt;="http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt; &lt;span &gt;xmlns:z&lt;/span&gt;&lt;span &gt;="http://schemas.microsoft.com/2003/10/Serialization/"&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Children&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Child&lt;/span&gt; &lt;span &gt;z:Id&lt;/span&gt;&lt;span &gt;="i2"&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;John&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;ParentRef&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;z:Ref&lt;/span&gt;&lt;span &gt;="i1"&lt;/span&gt;&lt;/font&gt;&lt;span &gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Child&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Child&lt;/span&gt; &lt;span &gt;z:Id&lt;/span&gt;&lt;span &gt;="i3"&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;Alice&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;ParentRef&lt;/span&gt; &lt;font style="background-color: #ffff00"&gt;&lt;span &gt;z:Ref&lt;/span&gt;&lt;span &gt;="i1"&lt;/span&gt;&lt;/font&gt;&lt;span &gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Child&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;    &lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Children&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    &lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;Baba&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Name&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;Parent&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;WCF的异常信息不准确给问题判断带来了很大的难度。但是，看清问题&lt;strong&gt;本质&lt;/strong&gt;，分析问题的&lt;strong&gt;特殊性&lt;/strong&gt;，加之一定经验的积累，就能很快的找准问题并解决之。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;假像总是会露出破绽的。例如，虽然异常信息提示可能是超时，但如果一调用服务马上返回错误，一般就不会是超时问题。如果错误提示说可能数据超过允许返回的大小，那么，试着返回一个单一个对象而非集合&amp;#8230;&amp;#8230;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;nbsp;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;当然，我们还是在不断努力，希望给大家带来提供更加易用的Visual Studio。&lt;/div&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;参考资源&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd456853%28VS.100%29.aspx" target="_blank"&gt;Working with POCO Entities&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx" target="_blank"&gt;ProxyDataContractResolver Class&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2120626.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/30/2120626.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/07/27/2117806.html</id><title type="text">大家都来搭架构 —— VS 2010 Layer Diagram (层图) 基本使用</title><summary type="text">Layer Diagram 最早应该出现在TechEd 2008，它不仅可以清晰展示应用程序架构，而且能够为帮助架构师随时检验代码之间的引用关系是否与层图一致，可谓既好看又好用。本文以Visual Studio 2010为例，一步步看来看如何为一个应用程序创建层图并且以此来对应用程序进行校验。</summary><published>2011-07-26T18:40:00Z</published><updated>2011-07-26T18:40:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/27/2117806.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/27/2117806.html"/><content type="html">&lt;p&gt;Layer Diagram 最早应该出现在TechEd 2008，它不仅可以清晰展示应用程序架构，而且能够为帮助架构师随时检验代码之间的引用关系是否与层图一致，可谓既好看又好用。本文以Visual Studio 2010为例，一步步看来看如何为一个应用程序创建层图并且以此来对应用程序进行校验。&lt;/p&gt;  &lt;p&gt;首先来看&amp;#8220;好看&amp;#8221;的部分，这是我为最近的一个小项目画的层图：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236111535.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236134859.png" border="0" height="484" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;呵呵，我美工功底较差，颜色问题啥的大家凑合一下吧；这个层图&amp;#8220;好看&amp;#8221;在于：&lt;/p&gt;  &lt;p&gt;其一，它把整个解决方案的架构信息清楚的呈现出来了（色块）&amp;#8212;&amp;#8212;从最底下的数据访问，中间的业务逻辑，夹在业务逻辑和ViewModel中间的服务，再到上面的ViewModel和UI，一目了然；&lt;/p&gt;  &lt;p&gt;其二，各层之间的依赖关系明确（箭头）&amp;#8212;&amp;#8212;服务层依赖于业务逻辑层，业务逻辑层依赖于数据访问层，这三个层都依赖于实体层，实体层不依赖于任何其它层&amp;#8230;&amp;#8230;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;怎么画出来的？以一个最简单的三层架构的代码为例：&lt;/p&gt;  &lt;p&gt;创建一个三层架构的项目，或者你敢不敢下载下面的代码试试^v^：&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;（UI-BLL-DAL）&lt;/p&gt;  &lt;p&gt;（由于是下载的代码，VS可能会有安全提示）&lt;/p&gt;  &lt;p&gt;点击主菜单Architecture &amp;#8211;&amp;gt; New Diagram:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236153266.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236173383.png" border="0" height="166" width="431" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;选择&amp;#8220;Layer Diagram&amp;#8221;，给它取个名字：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236198692.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236225047.png" border="0" height="484" width="488" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;此时，VS会要求我们建一个Modeling的项目来容纳层图。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236247848.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236269536.png" border="0" height="362" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;一样，取名，确定就行了。&lt;/p&gt;  &lt;p&gt;这样，我们的第一个层图就创建好了&amp;#8212;&amp;#8212;空的啊。&lt;/p&gt;  &lt;p&gt;让我们来给它添一些层。首先，从UI开始，点击工具箱里的层，然后，在层图设计器上点击一下，一个层就建好了。双击Layer1，改名叫&amp;#8220;UI&amp;#8221;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236287419.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236308060.png" border="0" height="274" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;同样操作，我们为BLL、DAL和Entity建立各自的层。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236317055.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236332779.png" border="0" height="326" width="379" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;为层与层之间设置依赖关系。从工具箱选择&amp;#8220;依赖&amp;#8221;（单向箭头），从UI画向BLL，表示：UI对BLL有直接依赖。同样的方法，让BLL依赖于DAL，这三个层同时依赖于Entity。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236341218.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236369974.png" border="0" height="313" width="371" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;接下来，我们就要在层与实体项目之间建立映射。这里有一些选项，我们可以将层映射到文件、Assemblies、命名空间、类等，映射关系的建立也可以通过解决方案浏览器或者架构浏览器来完成。这里这使用架构浏览器为例，在层与命名空间之间建立映射关系。&lt;/p&gt;  &lt;p&gt;打开架构浏览器：主菜单 &amp;#8211;&amp;gt; Architecture &amp;#8211;&amp;gt; Windows &amp;#8211;&amp;gt; Architecture Explorer。&lt;/p&gt;  &lt;p&gt;点击Class View &amp;#8211;&amp;gt; 然后，把Simple3Tier.UI拽到UI层上，这样，我们就把Simple3Tier.UI映射到了UI层上。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236385839.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236408116.png" border="0" height="653" width="585" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;这样，我们就可以看到UI层右上角多了一个1，表明它与一个对象形成了映射关系，同时，点击层图上的UI，在右侧的层浏览器（Layer Explorer）中，我们可以看到它到底映射到哪一个对象。&lt;/p&gt;  &lt;p&gt;同样，我们把BLL/DAL/Entity分别映射到对应的图形上。我们这样项目的层图就大功告成了：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236426838.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236445735.png" border="0" height="353" width="644" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;完成了层图，就可以用来验证应用程序了。让我们右击空白区域，点击&amp;#8220;验证架构&amp;#8221;。如果你是下载的上文中提供的项目，那么，就应该&amp;#8220;中招&amp;#8221;了^v^&amp;#8212;&amp;#8212;3个错误：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236467455.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236493603.png" border="0" height="484" width="629" /&gt;&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;我们稍微看一下错误信息：看来是因为UI对DAL有依赖。而我们的层图中没有这样的依赖关系&amp;#8212;&amp;#8212;或者不允许这种依赖关系的存在。&lt;/p&gt;  &lt;p&gt;因此，至少有两种改法，第一，给层图添加一个依赖关系：从UI到DAL。我想大部分时间我们不会这么做，大家懂的；第二，修改代码。&lt;/p&gt;  &lt;p&gt;我们以修改代码为例，双击一行错误，层图会帮助我们定位到代码（Main方法），修改代码如下：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;            BizClass bizClass = &lt;span &gt;new&lt;/span&gt; BizClass();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;            var result = bizClass.GetMessage();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;// DAL.DataClass dataClass = new DAL.DataClass();&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            &lt;span &gt;// var result = dataClass.GetMessager().Message;            &lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            System.Console.WriteLine(result);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;右击错误，点击&amp;#8220;Go to&amp;#8221;，选择&amp;#8220;层图&amp;#8221;。回到层图后，重点右击验证。再看Error List，错误就没有了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;层图可以帮助我们校验代码依赖关系。当代码依赖关系与架构不符时，层图可以帮助我们找到错误代码，以保证整个架构不被破坏。这一点在大型项目多人开发时非常重要。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;如果想要在Build时自动进行架构校验，只要修改层图文件的Build Action属性为Validate就可以了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236516437.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107270236538157.png" border="0" height="484" width="232" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;资源：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Existing Layer Diagrams: &lt;a href="http://visualstudiogallery.msdn.microsoft.com/237f823c-45b4-4f1f-b9e2-607fe66eaae7" target="_blank"&gt;Application Architecture Guide Layer Diagrams&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Skinner&amp;#8217;s Blog: &lt;a href="http://blogs.msdn.com/b/camerons/archive/2008/07/11/layer-diagram.aspx" target="_blank"&gt;Layer Diagram&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;MSDN：&lt;a href="http://msdn.microsoft.com/en-us/library/dd418995.aspx" target="_blank"&gt;Layer Diagrams: Guidelines&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;MSDN: &lt;a href="http://msdn.microsoft.com/en-us/library/dd465141.aspx" target="_blank"&gt;How to: Create Layer Diagrams from Artifacts&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2117806.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/27/2117806.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/07/24/2115199.html</id><title type="text">基于Entity Framework 4.1实现一个适用于单元测试的MockDbContext(下)</title><summary type="text">本文接上篇，分析了原实现方法的问题，以新的思路设计一个接口，实现了一个方便单元测试使用的MockDbContext。</summary><published>2011-07-23T21:13:00Z</published><updated>2011-07-23T21:13:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/24/2115199.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/24/2115199.html"/><content type="html">&lt;p&gt;上篇中提到，我们在利用修改做的MockDbContext进行单元测试时，在获取数据时出现了问题。原因在于，在写获取的代码时，我们直接调用了DbContext的Set&amp;lt;T&amp;gt;()方法，而这个方法会从数据库中取数据。&lt;/p&gt;  &lt;p&gt;我们来看一个例子：&lt;/p&gt;  &lt;p&gt;这是一个简化的业务逻辑代码来获取全部的Handbook：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; IList&amp;lt;Handbook&amp;gt; GetMyHandbooks()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;var handbookSet = dbContext.Set&amp;lt;Handbook&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;return&lt;/span&gt; handbookSet.ToList();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;对应的单元测试：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        [TestMethod]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; GetMyHandBooksTest()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            var mockDbContext = &lt;span &gt;new&lt;/span&gt; MockMTBContainer();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            BizHandbook target = &lt;span &gt;new&lt;/span&gt; BizHandbook(mockDbContext);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            mockDbContext.Handbooks1.Add(&lt;span &gt;new&lt;/span&gt; Handbook() { HandbookID = 1 });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            mockDbContext.Handbooks1.Add(&lt;span &gt;new&lt;/span&gt; Handbook() { HandbookID = 2 });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            var result = target.GetMyHandbooks();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;            Assert.IsNotNull(result);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            Assert.AreEqual(2, result.Count);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;行4-5创建一个业务逻辑对象，也是我们的测试目标target，第5行中的构造函数以以mockDbContext为参数，此业务逻辑对象会使用mockDbContext而非默认的DbContext。第10行代码调用了GetMyHandbooks()方法。第11行和12行分别验能够获得结果并且结果集中有两个对象。大家已经知道使用上篇中的mockDbContext，这个单元测试会Fail。第12行Assert预期为2，实际为0。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;直接问题出在GetMyHandbooks方法的return语句中的.ToList()方法。这是一个System.Linq中提供的扩展方法，它所做的事情是：调用Expression对象进行数据查询得到一个IEnumerator&amp;lt;TEntity&amp;gt;，然后创建一个List&amp;lt;TEntity&amp;gt;对象，进行迭代将数据填入列表，最后返回。谁提供了Expression？DbContext中的DbSet&amp;lt;TEntity&amp;gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;在上篇中，我们仅仅是简单的重写了（或者说，废掉了^_^）DbContext的SaveChanges()，但是在查询数据的时候，Expression仍然会从对应的DB中获取数据。另外，对Local属性的理解也有问题，Local里并不是所有数据，但是新增或变更过的数据。于是，单元测试12行出现actual＝0的现象也就得到合理解释了。看来，之前的想法太过简单了。需要重新构思一个mockDbContext。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;由于DbSet&amp;lt;TEntity&amp;gt;的Expression属性不是virtual属性，简单重写一下Expression的想法行不通。曾经想过用一个同名属性覆盖它，但是，这样应该也有问题（之所以说应该，是因为没有试过），因为DbContext中使用的都是DbSet&amp;lt;TEntity&amp;gt;类，会调用原来的Expression属性的。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;通过以上的分析，我们知道，要让MockDbContext好用，涉及两个类：DbContext和DbSet&amp;lt;TEntity&amp;gt;，因此，现在的思路是，实现两个新的类，替换掉它们。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;由于要在业务逻辑不作任何修改的情况下调用DbContext和MockDbContext，这两个类要求实现同一接口；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;同理，DbSet&amp;lt;TEntity&amp;gt;和新写的类（叫MockDbSet&amp;lt;TEntity&amp;gt;吧）同样也要实现同一个接口。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;我们从MockDbSet&amp;lt;TEntity&amp;gt;着手。由于DbSet&amp;lt;TEntity&amp;gt;实现了IDbSet&amp;lt;TEntity&amp;gt;接口，因此，对于MockDbSet&amp;lt;TEntity&amp;gt;来说，实现IDbSet&amp;lt;TEntity&amp;gt;即可（这个类方法比较多，但都是非常基本的方法，文章最后有下载）：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MockDbSet&amp;lt;TEntity&amp;gt; : IDbSet&amp;lt;TEntity&amp;gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;where&lt;/span&gt; TEntity : &lt;span &gt;class&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; ObservableCollection&amp;lt;TEntity&amp;gt; storage = &lt;span &gt;new&lt;/span&gt; ObservableCollection&amp;lt;TEntity&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TEntity Add(TEntity entity)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (entity != &lt;span &gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                storage.Add(entity);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; entity;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TEntity Attach(TEntity entity)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;            storage.Add(entity);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; entity;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TDerivedEntity Create&amp;lt;TDerivedEntity&amp;gt;() &lt;span &gt;where&lt;/span&gt; TDerivedEntity : &lt;span &gt;class&lt;/span&gt;, TEntity&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; Activator.CreateInstance&amp;lt;TDerivedEntity&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TEntity Create()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; Activator.CreateInstance&amp;lt;TEntity&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TEntity Find(&lt;span &gt;params&lt;/span&gt; &lt;span &gt;object&lt;/span&gt;[] keyValues)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  33:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;            &lt;span &gt;int&lt;/span&gt; currentKeyPropertyIndex;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  35:  &lt;/span&gt;            &lt;span &gt;foreach&lt;/span&gt; (var entity &lt;span &gt;in&lt;/span&gt; storage)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  37:  &lt;/span&gt;                currentKeyPropertyIndex = 0;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;                &lt;span &gt;foreach&lt;/span&gt; (var property &lt;span &gt;in&lt;/span&gt; &lt;span &gt;typeof&lt;/span&gt;(TEntity).GetProperties())&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  39:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;                    &lt;span &gt;if&lt;/span&gt; (property.Name.Contains(&lt;span &gt;&amp;quot;ID&amp;quot;&lt;/span&gt;))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  41:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;                        &lt;span &gt;if&lt;/span&gt; (property.GetValue(entity).Equals(keyValues[currentKeyPropertyIndex]))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  43:  &lt;/span&gt;                        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;                            currentKeyPropertyIndex++;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  45:  &lt;/span&gt;                            &lt;span &gt;if&lt;/span&gt; (currentKeyPropertyIndex == keyValues.Length)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;                            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  47:  &lt;/span&gt;                                &lt;span &gt;return&lt;/span&gt; entity;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;                            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  49:  &lt;/span&gt;                        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  51:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  53:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; &lt;span &gt;null&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  55:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; System.Collections.ObjectModel.ObservableCollection&amp;lt;TEntity&amp;gt; Local&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  57:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;            get { &lt;span &gt;return&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ObservableCollection&amp;lt;TEntity&amp;gt;(&lt;span &gt;this&lt;/span&gt;.storage); }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  59:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  61:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; TEntity Remove(TEntity entity)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  63:  &lt;/span&gt;            storage.Remove(entity);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; entity;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  65:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  67:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IEnumerator&amp;lt;TEntity&amp;gt; GetEnumerator()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  69:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; &lt;span &gt;this&lt;/span&gt;.storage.GetEnumerator();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  71:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  73:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  74:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; &lt;span &gt;this&lt;/span&gt;.storage.GetEnumerator();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  75:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  76:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  77:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; Type ElementType&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  78:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  79:  &lt;/span&gt;            get&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  80:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  81:  &lt;/span&gt;                &lt;span &gt;return&lt;/span&gt; storage.AsQueryable().ElementType;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  82:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  83:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  84:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  85:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; System.Linq.Expressions.Expression Expression&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  86:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  87:  &lt;/span&gt;            get&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  88:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  89:  &lt;/span&gt;                &lt;span &gt;return&lt;/span&gt; storage.AsQueryable().Expression;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  90:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  91:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  92:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  93:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IQueryProvider Provider&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  94:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  95:  &lt;/span&gt;            get&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  96:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  97:  &lt;/span&gt;                &lt;span &gt;return&lt;/span&gt; storage.AsQueryable().Provider;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  98:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  99:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 100:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;延续前文思路，在第4行添加了一个ObservableCollection&amp;lt;T&amp;gt;的集合，用作本地存储；增、删、改全部针对这个集合来完成。第85到91行，在返回Expression的时候，把storage.AsQueryable()的表达式返回出去，这样，查询的的时候就会获取到查询storage中元素的表达式。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;接下来，我们要把使用DbSet&amp;lt;TEntity&amp;gt;的DbContext和使用MockDbSet&amp;lt;TEntity&amp;gt;的MockDbContext统一起来。查看一下DbContext&amp;#8230;&amp;#8230;呃~没有实现任何接口-.-||（曾经有位伟人说过&amp;#8230;&amp;#8230;算了，不说了）既然没有接口，我们就来创建一个：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;using&lt;/span&gt; System.Data.Entity;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;namespace&lt;/span&gt; MTB.Data&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;interface&lt;/span&gt; ITestableDbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;IDbSet&amp;lt;TEntity&amp;gt; Set&amp;lt;TEntity&amp;gt;() &lt;span &gt;where&lt;/span&gt; TEntity : &lt;span &gt;class&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;int&lt;/span&gt; SaveChanges();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;这个接口做两件事，第一，可以实现数据持久化——SaveChanges()。第二，可以获取到IDbSet&amp;lt;TEntity&amp;gt;集合以对集合中数据进行操作。然后，做两件事：第一，让具体的DbContext实现这个接口；第二，写一个MockDbContext实现这个接口。 &#xD;
  &lt;br /&gt;我们先来看DbContext实现接口的部分：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MTBContainer : DbContext, ITestableDbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; MTBContainer()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            : &lt;span &gt;base&lt;/span&gt;(&lt;span &gt;&amp;quot;name=MTBContainer&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; IDbSet&amp;lt;TEntity&amp;gt; Set&amp;lt;TEntity&amp;gt;() &lt;span &gt;where&lt;/span&gt; TEntity : &lt;span &gt;class&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; &lt;span &gt;base&lt;/span&gt;.Set&amp;lt;TEntity&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        &lt;span &gt;//... Other code...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IDbSet&amp;lt;Handbook&amp;gt; Handbooks1 { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IDbSet&amp;lt;Trip&amp;gt; Trips { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        &lt;span &gt;// ... more item&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;其中，第8到11行，虽然覆盖了Set&amp;lt;TEntity&amp;gt;()，但调用的仍然是DbContext类中的Set&amp;lt;TEntity&amp;gt;()方法；然后把对应的DbSet&amp;lt;TEntity对象集合全部改为IDbSet&amp;lt;TEntity&amp;gt;，大功告成。由于用的是Model First的EF4.1，因此，其实这个类是通过修改模板而来的。修改过的模板会在文章结束时附上。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;MockDbContext实现：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MockMTBContainer : DbContext, ITestableDbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; MockMTBContainer()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            : &lt;span &gt;base&lt;/span&gt;(&lt;span &gt;&amp;quot;name=MTBContainer&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            Handbooks1 = &lt;span &gt;new&lt;/span&gt; MockDbSet&amp;lt;Handbook&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            Trips = &lt;span &gt;new&lt;/span&gt; MockDbSet&amp;lt;Trip&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;// Other code&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; IDbSet&amp;lt;TEntity&amp;gt; Set&amp;lt;TEntity&amp;gt;() &lt;span &gt;where&lt;/span&gt; TEntity : &lt;span &gt;class&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;                &lt;span &gt;foreach&lt;/span&gt; (PropertyInfo property &lt;span &gt;in&lt;/span&gt; &lt;span &gt;typeof&lt;/span&gt;(MockMTBContainer).GetProperties())&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;                    &lt;span &gt;if&lt;/span&gt; (property.PropertyType == &lt;span &gt;typeof&lt;/span&gt;(IDbSet&amp;lt;TEntity&amp;gt;))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;                        &lt;span &gt;return&lt;/span&gt; property.GetValue(&lt;span &gt;this&lt;/span&gt;, &lt;span &gt;null&lt;/span&gt;) &lt;span &gt;as&lt;/span&gt; IDbSet&amp;lt;TEntity&amp;gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;                &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; Exception(&lt;span &gt;&amp;quot;Type collection not found&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; SaveChanges()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  31:  &lt;/span&gt;            &lt;span &gt;//Do nothing&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; 0;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  33:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  35:  &lt;/span&gt;        &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  37:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IDbSet&amp;lt;Handbook&amp;gt; Handbooks1 { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IDbSet&amp;lt;Trip&amp;gt; Trips { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  39:  &lt;/span&gt;        &lt;span &gt;// ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;这个MockDbContext同样继承自DbContext类（嗯，可以少写不少代码呢）。但是，覆盖了Set&amp;lt;TEntity&amp;gt;()方法；当然，第29到33行废掉SaveChanges()的事仍然不可不做——如果想让测试更全面一些，看看那些个增、删、改方法有没有忘调用SaveChanges()，利用这个重写设置一个标志为也不错啊&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none"  alt="Smile" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107240507222407.png" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Okay，一切就绪，我们把这一切综合起来使用：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;首先，业务逻辑：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; BizHandbook&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        ITestableDbContext dbContext = &lt;span &gt;null&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Constructions&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; BizHandbook()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            : &lt;span &gt;this&lt;/span&gt;(&lt;span &gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; BizHandbook(ITestableDbContext dbContextl)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (dbContext == &lt;span &gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  15:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;                dbContext = &lt;span &gt;new&lt;/span&gt; MTBContainer();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  17:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;            &lt;span &gt;this&lt;/span&gt;.dbContext = dbContext;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  19:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;        &lt;span &gt;#region&lt;/span&gt; Publich Methods&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  23:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; IList&amp;lt;Handbook&amp;gt; GetMyHandbooks()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  25:  &lt;/span&gt;            var handbookSet = dbContext.Set&amp;lt;Handbook&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; handbookSet.ToList();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  27:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;        &lt;span &gt;#endregion&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  29:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
第12行构造函数会要求一个实现了ITestableDbContext的对象，如果为null，那么使用默认的DbContext。增删改查一律该怎么写就怎么写。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;测试：&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;#8230;&amp;#8230;跟本而第二个代码片段一样，没有变化！（其实，MockDbContext变了）。&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&amp;#160;&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;Okay，小结时间：&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;我们创建了一个接口ITestableDbContext，并且写了一个MockDbContext类，来实现对调用EF4.1的业务逻辑代码的单元测试（红的部分）：&lt;/div&gt;&#xD;
&#xD;
&lt;div &gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107240507242241.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107240507259634.png" width="244" height="137" /&gt;&lt;/a&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;模板下载，使用的时候记得修改对应的using和inputFile变量——&lt;a href="https://skydrive.live.com/?cid=0f2c5d26f048ad24&amp;amp;sc=documents&amp;amp;uc=1&amp;amp;id=F2C5D26F048AD24%21491#"&gt;点击下载&lt;/a&gt;。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;内容：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;1. 使用IDbSet&amp;lt;T&amp;gt;的DbContext的模板；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;2. MockDbContext模板；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;3. MockDbSet&amp;lt;TEntity&amp;gt;类；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;4. ITestableDbContext接口；&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;对了，顺便提一下，在MockDbSet&amp;lt;TEntity&amp;gt;实现的时候，Find()方法为了方便起见，使用了一个Hack的方法来判断属性是否为Key属性——属性名称中是否含有ID。&lt;/p&gt;  &lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2115199.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/24/2115199.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/07/22/2113869.html</id><title type="text">基于Entity Framework 4.1实现一个适用于测试的MockDbContext(上)</title><summary type="text">最近用Entity Framework 4.1写点小项目，在写一个Mock的Repository的时候还走了些弯路，费了一些时间，在此把过程写出来，希望能帮大家节省一点时间。</summary><published>2011-07-22T06:46:00Z</published><updated>2011-07-22T06:46:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/22/2113869.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/22/2113869.html"/><content type="html">&#xD;
&lt;p&gt;&lt;em&gt;声明：我最近在微软加拿大开发中心工作，这是我个人的博客，跟公司没有关系。如果你在我的博客里看到我推荐微软的产品，就权当广告好了。&lt;/em&gt;    &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;我们在作一些CRUD相关的单元测试的时候，通常不会真的连接到数据库，而是写一个Mock的Repository，把Entity放到一个集合啊或者Hash table啊什么的里面。   &lt;br /&gt;最近用Entity Framework 4.1写点小项目，在写一个Mock的Repository的时候还走了些弯路，费了一些时间，在此把过程写出来，希望能帮大家节省一点时间。    &lt;br /&gt;项目中用的是Model First，在Database First模型中应该也适用，先设计完数据库模型，生成数据库和两个.tt文件&amp;#8212;&amp;#8212;MTBDbContext.Context.tt和MTBDbContext.tt。第一个文件里是一个DbContext类，担任数据持久化操作；第二个文件里是实体类。这两个文件原来与数据库模型是在同一个项目中的，做了一些小动作，把它们分开了^_^。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107221442481646.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107221442494337.png" width="280" height="684" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;根据这样的结构，写MockDbContext的思路是这样子的：以添加一个实体类为例，我们通常会写这样的代码：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; AddBatch(Handbook handbook)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;dbContext.Set&amp;lt;Handbook&amp;gt;().Add(handbook);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;dbContext.SaveChanges();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;如果直接调用EF4.1的DbContext，在调用 DbContext里的SaveChanges()，数据就会被固化到数据库里。但我们相信，只要数据能够在本地保存，通过DbContext，它就一定会存到数据库里，因此，测试时没有必要把数据库写到数据库中去，只要在本地进行验证。&#xD;
  &lt;br /&gt;综上，我们需要的MockDbContext只要满足两个条件：第一，SaveChanges()不把数据固化到数据库，而是存在本地；第二，可以在本地作数据验证。&#xD;
&#xD;
  &lt;br /&gt;我们首先来满足第一个条件。打开DbContext看一下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MTBContainer : DbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; MTBContainer()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;: &lt;span &gt;base&lt;/span&gt;(&lt;span &gt;"name=MTBContainer"&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;protected&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; UnintentionalCodeFirstException();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; DbSet&amp;lt;Handbook&amp;gt; Handbooks1 { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; DbSet&amp;lt;Trip&amp;gt; Trips { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;// &amp;#8230; more DbSet&amp;lt;T&amp;gt;...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;这个类信息不多，因此推测逻辑都在其基类DbContext里。因此，在Object Browser里打开DbContext看了一下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; DbContext : IDisposable, IObjectContextAdapter&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;protected&lt;/span&gt; DbContext();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;//&amp;#8230; more constructors&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;// Other code ...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;virtual&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; SaveChanges();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; DbSet&amp;lt;TEntity&amp;gt; Set&amp;lt;TEntity&amp;gt;() &lt;span &gt;where&lt;/span&gt; TEntity : &lt;span &gt;class&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; DbSet Set(Type entityType);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;//...&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;里面有一个SaveChanges()方法，而且还是虚的。这样，事情就简单了（起初是这样认为的，也是从这里开始走的弯路）：重写一下SaveChanges()方法，让它什么都不做，它不就不会把数据存回数据库了吗？OK，第一个条件基本达成。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第二个条件，本地验证。由于实体类对象都保存在DbSet&amp;lt;T&amp;gt;里，而DbSet&amp;lt;T&amp;gt;里有一个ObservableCollection&amp;lt;T&amp;gt;类型的Local属性保存的正是本地实体类对象（这个理解有问题的）。这样，事情就好办了，我们写测试验证的时候直接验证这里的结果就行了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;按着这个思路，复制粘贴了一份MTBDbContext.Context.tt，改名为MockMTBDbContext.Context.tt并且放到了对应的单元测试项目中。然后，稍微修改了一下模板：添加了一些using的命名空间，改了生存的类名和构造函数名，然后就是重点添加一个什么都不做的SaveChanges()的重写方法&amp;#8212;&amp;#8212;保存，自动生成代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;...         &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MockMTBContainer : DbContext, ITestableDbContext&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; MockMTBContainer()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;: &lt;span &gt;base&lt;/span&gt;(&lt;span &gt;"name=MTBContainer"&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;override&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; SaveChanges()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;//Do nothing&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;return&lt;/span&gt; 0;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;...    &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; DbSet&amp;lt;Handbook&amp;gt; Handbooks1 { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; DbSet&amp;lt;Trip&amp;gt; Trips { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&amp;#8230;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;接下来，就写了一个测试代码来看看一个基本操作：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;///A test for Add&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;///&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;[TestMethod()]&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; AddTest()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;var mockDbContext = &lt;span &gt;new&lt;/span&gt; MockMTBContainer();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;BizHandbook target = &lt;span &gt;new&lt;/span&gt; BizHandbook(mockDbContext); &lt;span &gt;// use mockDbContext here.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;Handbook handbook = &lt;span &gt;new&lt;/span&gt; Handbook();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;target.Add(handbook);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;Assert.AreEqual&amp;lt;&lt;span &gt;int&lt;/span&gt;&amp;gt;(1, mockDbContext.Handbooks1.Local.Count); &lt;span &gt;// see whether the entity object's added&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;跑Case，成功Pass。哈。没想到这么轻松。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;但是&amp;#8230;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;但是&amp;#8230;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;CRUD四项操作中，CUD都可以测试，R（Retrieve）的时候，却怎么也得不到结果&amp;#8230;&amp;#8230;添加的记录在Local可以看到，但是.ToList()的时候怎么都是null。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;＝＝＝＝＝&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;下篇解释了错误的原因，并且重新设计了一个接口以完成目标。&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/24/2115199.html"&gt;点击继续...&lt;/a&gt;&lt;/p&gt; &#xD;
 &#xD;
&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2113869.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/22/2113869.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xiaomi7732/archive/2011/07/05/2097942.html</id><title type="text">利用IProgress轻松搞定进度条编程</title><summary type="text">毫无疑问，当一个任务需要较长时间才能完成进，如果有一个进度条显示进度，会比简单的显示一个Please Wait要让人感觉好很多。然而，一旦涉及进度条，那么，程序至少需要同时做两件事（好吧，也许叫异步的做两件事更确切一点）：第一，完成任务本身；第二，计算进度并更新UI。在C# 5.0 Aysnc中提供的IProgress类，为进度条编程提供了便捷的方法。三步即可完成一个简单的进度条...</summary><published>2011-07-05T01:09:00Z</published><updated>2011-07-05T01:09:00Z</updated><author><name>Saar</name><uri>http://www.cnblogs.com/xiaomi7732/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/05/2097942.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/05/2097942.html"/><content type="html">&#xD;
&lt;p&gt;毫无疑问，当一个任务需要较长时间才能完成进，如果有一个进度条显示进度，会比简单的显示一个Please Wait要让人感觉好很多。    &lt;br /&gt;然而，一旦涉及进度条，那么，程序至少需要同时做两件事（好吧，也许叫异步的做两件事更确切一点）：第一，完成任务本身；第二，计算进度并更新UI。在C# 5.0 Aysnc中提供的IProgress&amp;lt;T&amp;gt;类，为进度条编程提供了便捷的方法。三步即可完成一个简单的进度条。     &lt;br /&gt;下面的示例基于Async CTP制作。要能编译、运行示例，需要以下准备：&lt;/p&gt;  &lt;ol&gt;   &lt;ol&gt;&lt;li&gt;Visual Studio 2010 SP1. &lt;/li&gt;&lt;li&gt;Async CTP(SP1 Refresh) &lt;/li&gt;&lt;li&gt;一个WPF应用程序，并且有一个进度条，顺便给进度条取个名，例如progressBar之类的 :-) &lt;/li&gt;   &lt;/ol&gt; &lt;/ol&gt;  &lt;p&gt;如果你还不知道Async是什么，&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/06/27/AsyncDemo.html" target="_blank"&gt;点这里&lt;/a&gt;。     &lt;br /&gt;好了，这样，我们就可以开始示例了。     &lt;br /&gt;第一步，写一个类，用于存放参数，我们用这些参数来计算进度。一个最简单的例子就是有两个整数值，一个是当前完成的值，另一个是总值。所以，我们就有了这样一个类：&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;//Step 1: Have a class to store current value / total value.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; ProgressPartialResult&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            &lt;span &gt;public&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; Current { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            &lt;span &gt;public&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; Total { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;有些时候，计算进度可能相当的复杂，但是，原则是一样的，把需要的参数全部做在这个类里就行了。当然，也有一种简单的极品：这个类就是一个System.Integer :-)那你就不用自己写了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;第二步，创建一个IProgress&amp;lt;T&amp;gt;的对像，其中，T就是我们刚才创建的类，并且添加相应的处理逻辑，用来处理当进度更新发生时要做的事情。示例中，一旦进度更新，我们就更新UI里的进度条。计算也很简单：当前值/总值*100。&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; DoProgress()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;//Step 2: Create an object of IProgress&amp;lt;T&amp;gt; to trace the progress &amp;amp; add event handler when new progress reported.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            var progress = &lt;span &gt;new&lt;/span&gt; Progress&amp;lt;ProgressPartialResult&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            progress.ProgressChanged += &lt;span &gt;new&lt;/span&gt; ProgressEventHandler&amp;lt;ProgressPartialResult&amp;gt;(progress_ProgressChanged);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;            &lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;            &lt;span &gt;//Step 3: Call async logic with progress report.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;            DoSomething(progress);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;        &lt;span &gt;void&lt;/span&gt; progress_ProgressChanged(&lt;span &gt;object&lt;/span&gt; sender, MainWindow.ProgressPartialResult &lt;span &gt;value&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            progressBar.Value = (&lt;span &gt;float&lt;/span&gt;)&lt;span &gt;value&lt;/span&gt;.Current / &lt;span &gt;value&lt;/span&gt;.Total * 100;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;好了，我想你已经知道第三步要做什么了：异步完成任务并且汇报进度。&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;   1:  &lt;/span&gt;        &lt;span &gt;private&lt;/span&gt; async &lt;span &gt;void&lt;/span&gt; DoSomething(IProgress&amp;lt;ProgressPartialResult&amp;gt; progress)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   3:  &lt;/span&gt;            &lt;span &gt;int&lt;/span&gt; total = 100;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;            &lt;span &gt;for&lt;/span&gt; (&lt;span &gt;int&lt;/span&gt; i = 0; i &amp;lt;= total; i++)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   5:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;                await TaskEx.Delay(20); &lt;span &gt;//Do things for 0.02 seconds.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   7:  &lt;/span&gt;                &lt;span &gt;//Report the progress&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt; (progress != &lt;span &gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;   9:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;                    progress.Report(&lt;span &gt;new&lt;/span&gt; ProgressPartialResult() { Current = i + 1, Total = total });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  11:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;  13:  &lt;/span&gt;            progress.Report(&lt;span &gt;new&lt;/span&gt; ProgressPartialResult() { Current = 0, Total = total });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;稍微看一下代码，我们假设总量是100，进度for循环以后，首先做任务本身，我们假设每次做0.02秒。然后，就汇报一下进度。当退出循环以后，把进度置为0。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;整理一下，整个事情其实是这样的，进度条编程围绕IProgress&amp;lt;T&amp;gt;的对象展开。每当我们在异步的做事的时候，我们就调用Report方法汇报一下进度，进度的参数我们通过一个预先定义好的类来传递。Report()方法会触发ProgressChanged事件，于是，就会调用事件处理者(Handler)逻辑。处理者则根据传递进来的参数，计算出当前的进度，并且做程序员预期它做的事，例如，更新UI上的进度条之类的。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;大家可以试一下进度条行进时拖动UI做点别的事玩玩^v^希望本文能够给你带来一些娱乐 :-)&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;贴个完整的Code Behind。UI部分大家就自行搞定吧。最最后面附简陋的应用程序贴图。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;using&lt;/span&gt; System;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;using&lt;/span&gt; System.Threading.Tasks;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;using&lt;/span&gt; System.Windows;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;namespace&lt;/span&gt; WpfApplication3&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;/// Interaction logic for MainWindow.xaml&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;partial&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; MainWindow : Window&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; MainWindow()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;InitializeComponent();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;this&lt;/span&gt;.DoProgress();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;//Step 1: Have a class to store current value / total value.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; ProgressPartialResult&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; Current { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; Total { get; set; }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;private&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; DoProgress()&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;//Step 2: Create an object of IProgress&amp;lt;T&amp;gt; to trace the progress &amp;amp; add event handler when new progress reported.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;var progress = &lt;span &gt;new&lt;/span&gt; Progress&amp;lt;ProgressPartialResult&amp;gt;();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;progress.ProgressChanged += &lt;span &gt;new&lt;/span&gt; ProgressEventHandler&amp;lt;ProgressPartialResult&amp;gt;(progress_ProgressChanged);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;//Step 3: Call async logic with progress report.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;DoSomething(progress);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;void&lt;/span&gt; progress_ProgressChanged(&lt;span &gt;object&lt;/span&gt; sender, MainWindow.ProgressPartialResult &lt;span &gt;value&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;progressBar.Value = (&lt;span &gt;float&lt;/span&gt;)&lt;span &gt;value&lt;/span&gt;.Current / &lt;span &gt;value&lt;/span&gt;.Total * 100;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;private&lt;/span&gt; async &lt;span &gt;void&lt;/span&gt; DoSomething(IProgress&amp;lt;ProgressPartialResult&amp;gt; progress)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;int&lt;/span&gt; total = 100;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;for&lt;/span&gt; (&lt;span &gt;int&lt;/span&gt; i = 0; i &amp;lt;= total; i++)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;await TaskEx.Delay(20); &lt;span &gt;//Do things for 2 seconds.&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;span &gt;//Report the progress&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;if&lt;/span&gt; (progress != &lt;span &gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;progress.Report(&lt;span &gt;new&lt;/span&gt; ProgressPartialResult() { Current = i + 1, Total = total });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;progress.Report(&lt;span &gt;new&lt;/span&gt; ProgressPartialResult() { Current = 0, Total = total });&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;}&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre &gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&#xD;
&lt;a href="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107050905276418.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="ProgressBar" border="0" alt="ProgressBar" src="http://images.cnblogs.com/cnblogs_com/xiaomi7732/201107/201107050905297300.png" width="528" height="355" /&gt;&lt;/a&gt; &#xD;
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;7/5：关于原文的一点点补充：&lt;/p&gt;&lt;p&gt;前文提到，进度条编程围绕IProress&amp;lt;T&amp;gt;展开。那么，为什么我们需要这个接口，换句话说，IProgress&amp;lt;T&amp;gt;给我们带来了什么？个人的理解如下，如果我们要异步的完成一个任务，例如DoSomething，并且我们已经有一系列函数可以帮且我们完成这个任务了，那么，调用这个函数时，我们可能会接触到以下一些函数的签名：&lt;/p&gt;&lt;p&gt;void DoSomething();&lt;/p&gt;&lt;p&gt;Task DoSomethingAsync();&lt;/p&gt;&lt;p&gt;Task DoSomethingAsync(CancellationToken ct);&lt;/p&gt;&lt;p&gt;Task DoSomethingAsync(CancellationToken ct, IProgress&amp;lt;int&amp;gt; progress);&lt;/p&gt;&lt;p&gt;再如果一下，如果我们想要知道DoSomething的进度，选哪一个会更合理一些？&amp;#8230;&amp;#8230;好吧，每个人都有选择的权力^v^大家自己参？OK。&lt;/p&gt;&lt;p&gt;其实这四个函数就像四个员工，第一个员工闷头干活，什么都不管；第二个会找别人干活，他本身负责协调，适合同一时间多做几件事（好同志啊），但是，一件活他一旦开始做了，天塌下来他也会继续做；第三个员工，跟二个差不多，只是随叫随停；第四个不仅随叫随停，而且，经常汇报进度。&lt;/p&gt;&lt;p&gt;所以，回到IProgress&amp;lt;T&amp;gt;上来，因为有了它，我们调用有它的函数时，虽然不知道执行的细节，仍然可以轻易的知道事态的进度；在写函数时，如果想要提供一个&amp;#8220;进度友好&amp;#8221;的函数，不管是给自己还是给别人用，把IProgress&amp;lt;T&amp;gt;作为参数都是一个不错的选择。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/xiaomi7732/aggbug/2097942.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xiaomi7732/archive/2011/07/05/2097942.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
