<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_鹤冲天</title><subtitle type="text">登高远眺，烟雾缭绕，江山飘摇。忆青春年少，死无所惧，也曾把那天宫大闹。玉皇老兄，王母大嫂，王侯将相皆求饶。而如今，两鬓白发飘，年事已高。</subtitle><id>http://feed.cnblogs.com/blog/u/59407/rss</id><updated>2012-04-27T10:05:33Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/59407/rss"/><entry><id>http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html</id><title type="text">c# 扩展方法 奇思妙用 高级篇 九：OrderBy(string propertyName, bool desc)</title><summary type="text">如题，本文实现 OrderBy(string propertyName, bool desc) 扩展方法，以弥补 Linq 原生排序方法的不足</summary><published>2012-01-15T10:41:00Z</published><updated>2012-01-15T10:41:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html"/><content type="html">&lt;p&gt;下面是 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb293129.aspx"&gt;Queryable 类&lt;/a&gt; 中最常用的两个排序的扩展方法：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IOrderedQueryable&amp;lt;TSource&amp;gt; OrderBy&amp;lt;TSource, TKey&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;TSource&amp;gt; source, Expression&amp;lt;Func&amp;lt;TSource, TKey&amp;gt;&amp;gt; keySelector);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IOrderedQueryable&amp;lt;TSource&amp;gt; OrderByDescending&amp;lt;TSource, TKey&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;TSource&amp;gt; source, Expression&amp;lt;Func&amp;lt;TSource, TKey&amp;gt;&amp;gt; keySelector);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&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;比如 web 应用中有如下 Url：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://demo.highsoft.cc/orders?orderby=OrderDate&amp;amp;desc=true"&gt;~/orders?orderby=OrderDate&amp;amp;desc=true&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;在代码中我们如何写出强类型的查询？&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        IQueryable&amp;lt;Order&amp;gt; query = &lt;span style="color: #008000"&gt;/**/&lt;/span&gt;;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName = &lt;span style="color: #008000"&gt;/*从请求中获取，OrderDate*/&lt;/span&gt;;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; desc = &lt;span style="color: #008000"&gt;/*从请求中获取，true*/&lt;/span&gt;;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; data = query.Where(&lt;span style="color: #008000"&gt;/*TODO: 如何写*/&lt;/span&gt;).ToArray();      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;单凭 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb293129.aspx"&gt;Queryable 类&lt;/a&gt; 中定义的 OrderBy 和 OrderByDescending， 是不可能简单直接写出来的，除非硬编码。&lt;/p&gt;&lt;p&gt;那有如此做到灵活呢？我们从 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb293129.aspx"&gt;Queryable 类&lt;/a&gt; 定义的 OrderBy 和 OrderByDescending 方法下手，它们均有一个 Expression&amp;lt;Func&amp;lt;TSource, TKey&amp;gt;&amp;gt; 类型的 keySelector 参数。&lt;/p&gt;&lt;p&gt;先来试下能不能动态构建一个 keySelector。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;动态构建 keySelector 参数&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;此部分要求对表达式树有一定了解，可查看：&lt;a href="http://msdn.microsoft.com/zh-cn/library/bb397951(v=VS.100).aspx"&gt;http://msdn.microsoft.com/zh-cn/library/bb397951(v=VS.100).aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;代码则相当简单：   &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; type = &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Order);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; propertyName = &amp;quot;&lt;span style="color: #8b0000"&gt;OrderDate&lt;/span&gt;&amp;quot;;&lt;br/&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; param = Expression.Parameter(type, type.Name);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = Expression.Property(param, propertyName);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; keySelector = Expression.Lambda(body, param);        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;最后三行代码动态构造了一颗表达式树：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201201/201201151734341176.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/ldp615/201201/201201151734351425.png" width="392" height="87" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;和我们使用 lambda 表达式写出的效果是完全一样的：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201201/201201151735167689.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/ldp615/201201/20120115173524419.png" width="589" height="54" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这步比较顺利，下面来看如何调用：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;调用 OrderBy&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;直接传入调用是不行的：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        repository.OrderBy(keySelector);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;因为前面构建的 keySelector 是 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb359520.aspx"&gt;LambdaExpression &lt;/a&gt;类型的，而 OrderBy 要求是 Expression&amp;lt;Func&amp;lt;Order, DateTime&amp;gt;&amp;gt; 。&lt;/p&gt;&lt;p&gt;但实质上 keySelector 就是 OrderBy 要求的类型： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201201/201201151827213891.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/ldp615/201201/201201151827228459.png" width="608" height="67" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;因为强类型，居然不认自家人了！&lt;/p&gt;&lt;p&gt;可以通过强制类型转换来解决，编译运行都没问题：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        repository.OrderBy((Expression&amp;lt;Func&amp;lt;Order, DateTime&amp;gt;&amp;gt;)keySelector);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;但这样一来，又成了硬编码。&lt;/p&gt;&lt;p&gt;我们期望灵活，解决方法有很多种，这里只介绍最简单的一种，借助 .net 4 中 &lt;a href="http://msdn.microsoft.com/zh-cn/library/dd264741.aspx"&gt;dynamic&lt;/a&gt;：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; orderedQueryable = Queryable.OrderBy(repository, (&lt;span style="color: #0000ff"&gt;dynamic&lt;/span&gt;)keySelector);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;因为扩展方法是不能被动态调用的（Extension methods cannot be dynamically dispatched），所以写成上面样子。&lt;/p&gt;&lt;p&gt;或将 keySelector 声明为 &lt;a href="http://msdn.microsoft.com/zh-cn/library/dd264741.aspx"&gt;dynamic&lt;/a&gt;：   &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;dynamic&lt;/span&gt; keySelector = Expression.Lambda(body, param);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; orderedQueryable = Queryable.OrderBy(repository, keySelector);        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;OK，搞定！根据属性名排序太常用了，遂提取成了扩展方法：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OrderBy 扩展方法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;将上面代码整理下，扩展方法就出来了：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;font color="#008080"&gt;QueryableExtensions&lt;/font&gt; {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; OrderBy&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; queryable, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; OrderBy(queryable, propertyName, &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; OrderBy&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; queryable, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; desc) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; param = Expression.Parameter(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T));&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = Expression.Property(param, propertyName);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;dynamic&lt;/span&gt; keySelector = Expression.Lambda(body, param);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; desc ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector);&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;注意，上面代码执行没问题，但效率不好。因为每次都要动态生成表达式树，另外动态调用也会造成一定性能损失。&lt;/p&gt;&lt;p&gt;想提高效率的话，可把动态生成的表达式树缓存起来，参考如下：&lt;/p&gt;&lt;p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;font color="#008080"&gt;QueryableExtensions&lt;/font&gt; {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; OrderBy&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; queryable, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;font color="#008080"&gt;QueryableHelper&lt;/font&gt;&amp;lt;T&amp;gt;.OrderBy(queryable, propertyName, &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; OrderBy&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; queryable, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; desc) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;font color="#008080"&gt;QueryableHelper&lt;/font&gt;&amp;lt;T&amp;gt;.OrderBy(queryable, propertyName, desc);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;font color="#008080"&gt;QueryableHelper&lt;/font&gt;&amp;lt;T&amp;gt; {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, LambdaExpression&amp;gt; cache = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, LambdaExpression&amp;gt;();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; OrderBy(IQueryable&amp;lt;T&amp;gt; queryable, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; desc) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;dynamic&lt;/span&gt; keySelector = GetLambdaExpression(propertyName);&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; desc ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; LambdaExpression GetLambdaExpression(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (cache.ContainsKey(propertyName)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; cache[propertyName];&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; param = Expression.Parameter(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T));&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = Expression.Property(param, propertyName);&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; keySelector = Expression.Lambda(body, param);&lt;br/&gt;            cache[propertyName] = keySelector;&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; keySelector;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;这里并发不是多大问题，如若考虑，可使用 &lt;a href="http://msdn.microsoft.com/zh-cn/library/dd287191.aspx"&gt;ConcurrentDictionary&amp;lt;TKey, TValue&amp;gt; 类&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;很方便的：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; data1 = productRepository.OrderBy(&amp;quot;&lt;span style="color: #8b0000"&gt;Name&lt;/span&gt;&amp;quot;);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; data2 = orderRepository.OrderBy(&amp;quot;&lt;span style="color: #8b0000"&gt;OrderDate&lt;/span&gt;&amp;quot;, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;《&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html" target="_blank"&gt;c#扩展方法奇思妙用&lt;/a&gt;》系列文章已有 25 篇，欢迎&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html" target="_blank"&gt;阅读&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;PS：简单编码，快乐生活！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2322986.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/12/11/2284154.html</id><title type="text">Linq：切勿使用 Count() &amp;gt; 0 来判断集合非空</title><summary type="text">如题，使用 Linq 时切勿使用 Count() &gt; 0 来判断集合非空，这样做可能会带来严重的性能问题</summary><published>2011-12-11T12:51:00Z</published><updated>2011-12-11T12:51:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/12/11/2284154.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/12/11/2284154.html"/><content type="html">&lt;p&gt;Linq 出现之前，我们通常使用下面的方式来判断集合是否非空，即集合包含元素：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; array = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;[0];&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; b1 = array.Length &amp;gt; 0;&lt;br/&gt;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; list = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; b2 = list.Count &amp;gt; 0;&lt;br/&gt;&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; collection = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Collection&amp;lt;&lt;span style="color: #0000ff"&gt;double&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; b3 = collection.Count &amp;gt; 0;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;使用 Length 或 Count 属性，上面的写法没有问题。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;但到了 Linq 时代，Enumerable.Count 扩展方法“统一了“ Length 和 Count 属性，于是就有了下面判断非空的写法：&lt;/p&gt;&lt;p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SomeAction&amp;lt;T&amp;gt;(IEnumerable&amp;lt;T&amp;gt; source){&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (source.Count() &amp;gt; 0){&lt;br/&gt;        &lt;span style="color: #008000"&gt;//...&lt;/span&gt;&lt;br/&gt;    }&lt;span style="color: #008000"&gt;//...&lt;/span&gt;&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;这种写法可以，运行也正常，但&lt;strong&gt;&lt;font color="#c0504d"&gt;可能会产生非常严重的性能的问题&lt;/font&gt;&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;注意是可能，并不是一定，上面的方法如果传入的是 Array、List&amp;lt;T&amp;gt;或Collection&amp;lt;T&amp;gt;，不会有问题。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;那么什么时候会出问题呢？我们来看如下方法：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt; GetNums(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; start, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; count)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; end = start + count;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = start; i &amp;lt; end; i++)&lt;br/&gt;        yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; i;&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;如下调用时：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; nums = GetNums(0, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;.MaxValue);&lt;br/&gt;SomeAction(nums);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;执行速度会相当慢，我的电脑大约用了 70 秒的时间来执行 source.Count() &amp;gt; 0。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;分析下的话，你会发现 GetNums 第 5 行代码 yield return i 执行了 int.MaxValue 次，有必要吗？&lt;/p&gt;&lt;p&gt;其实只要返回一个元素我们就可以断定集合非空，完全不需要将所有的元素返回。&lt;/p&gt;&lt;p&gt;那又如何来判断呢？我们可以使用 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb337697.aspx" target="_blank"&gt;Enumerable.Any&lt;/a&gt; 扩展方法：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201112/201112112045376312.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" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201112/2011121120453965.png" width="760" height="314" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;将 SomeAction 方法修改如下：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SomeAction&amp;lt;T&amp;gt;(IEnumerable&amp;lt;T&amp;gt; source){&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(source.Any()){ &lt;span style="color: #008000"&gt;// 切勿使用 source.Count() &amp;gt; 0&lt;/span&gt;&lt;br/&gt;        &lt;span style="color: #008000"&gt;//...&lt;/span&gt;&lt;br/&gt;    }&lt;span style="color: #008000"&gt;//...&lt;/span&gt;&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;再次调用 ，你会发现执行时间可以忽略不计了。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;总结下规律，&lt;strong&gt;&lt;font color="#000000"&gt; Count() &amp;gt; 0 遇上 yeild return 必定会出现性能问题&lt;/font&gt;&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/bb337697.aspx"&gt;Enumerable.Any&lt;/a&gt; 扩展方法可以解决我们的问题，但这个方法在命名上似乎有些问题，总感觉有点不顺，如若判断集合为空：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!source.Any()) { &lt;span style="color: #008000"&gt;//...&lt;/span&gt;&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;! source.Any() 更显得绕口，我们可以新增两个扩展方法 IsEmpty、IsNotEmpty 来解决，请参考我的文章：&lt;/p&gt;&lt;p&gt;《 &lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html"&gt;c# 扩展方法奇思妙用基础篇十：IsEmpty、IsNotEmpty 扩展&lt;/a&gt; 》&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2284154.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/11/2284154.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html</id><title type="text">c# 扩展方法奇思妙用基础篇十：IsEmpty、IsNotEmpty 扩展</title><summary type="text">IsEmpty、IsNotEmpty 扩展方法，用来确定序列是否包含元素。</summary><published>2011-12-10T14:45:00Z</published><updated>2011-12-10T14:45:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html"/><content type="html">&lt;p&gt;这两个扩展方法很简单：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; EnumerableExtensions {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsEmpty&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; !source.Any();&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsNotEmpty&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; source.Any();&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/bb337697.aspx" target="_blank"&gt;Enumerable.Any&lt;/a&gt; 方法用来判断序列（或集合）是否包含元素，但这个名字不如 IsNotEmpty 更贴切，!source.Any() 更是绕口，于是便有了 IsEmpty 和 IsNotEmpty 两个扩展方法。&lt;/p&gt;&lt;p&gt;有一点要注意，不少朋友使用 &lt;font color="#c0504d"&gt;&lt;strong&gt;source.Count() &amp;gt; 0&lt;/strong&gt; &lt;/font&gt;来判断是否包含元素，&lt;strong&gt;&lt;font color="#c0504d"&gt;是不恰当的&lt;/font&gt;&lt;/strong&gt;，&lt;font color="#c0504d"&gt;&lt;strong&gt;可能会造成效率严重低下&lt;/strong&gt;&lt;/font&gt;，具体原因另撰文详述。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;div style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; background-color: #fff0f0; margin: 10px; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;strong&gt;《&lt;/strong&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html"&gt;&lt;strong&gt;c#扩展方法奇思妙用&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;》系统文章从 2009 年 08 月开始写起，到现在一共有了 25 篇，欢迎阅读：&lt;/strong&gt;   &lt;table style="margin: 15px" border="0" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;基础篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541376.html"&gt;中文处理&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/14/1546437.html"&gt;string 常用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/14/1552133.html"&gt;byte 常用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/01/27/random-extensions.html"&gt;Random 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/01/28/dictionary-extensions.html"&gt;Dictionary&amp;lt;TKey, TValue&amp;gt; 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/17/WhereIf-ExtensionMethod.html"&gt;WhereIf 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/18/IsBetween-ExtensionMethod.html"&gt;IsBetween 通用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/17/WhereIf-ExtensionMethod.html"&gt;WhereIf 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html"&gt;Distinct 扩展&lt;/a&gt;、 &lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html"&gt;IsEmpty、IsNotEmpty 扩展&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;高级篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/08/1541641.html"&gt;改进 Scottgu 的 &amp;quot;In&amp;quot; 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/12/1544688.html"&gt;Aggregate扩展其改进&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/17/1548369.html"&gt;Enumerable.Cast&amp;lt;T&amp;gt;应用&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/29/1555309.html"&gt;对扩展进行分组管理&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/09/02/1559020.html"&gt;ToString(string format) 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/11/08/1598596.html"&gt;WinForm 控件选择器&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/11/09/1599312.html"&gt;树”通用遍历器&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html"&gt;Type类扩展&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;变态篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/10/1542599.html"&gt;由Fibonacci数列引出“委托扩展”及“递推递归委托”&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/13/1545312.html"&gt;封装 if/else、swith/case及while&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/18/1549159.html"&gt;switch/case 组扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/26/1554524.html"&gt;string 的翻身革命&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;性能篇&lt;strong&gt;：&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/15/1546895.html"&gt;扩展方法性能初测&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;MVC篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2010/04/17/TextBoxFor.html"&gt;巧用扩展方法优先级，美化所有页面TextBoxFor文本框&lt;/a&gt; &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2283610.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/10/is-empty-and-is-not-empty-extension-methods.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/12/09/simple-create-a-complex-tree.html</id><title type="text">四行代码创建复杂（无限级）树</title><summary type="text">最近两三天一直在做树方面的基础工作，碰巧今天在博客园看到一篇关于动态创建树文章，粗略浏览下，感觉有不够强大。相比而言，感觉自己的方式更好些，只需要四行代码就可以创建一颗复杂的无限级树</summary><published>2011-12-09T12:38:00Z</published><updated>2011-12-09T12:38:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/12/09/simple-create-a-complex-tree.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/12/09/simple-create-a-complex-tree.html"/><content type="html">&lt;p&gt;最近两三天一直在做树方面的基础工作，碰巧今天在博客园看到一篇文章《&lt;a href="http://www.cnblogs.com/geyunfei/archive/2011/12/08/2280626.html"&gt;C#中一种通用的树的生成方式&lt;/a&gt;》，粗略浏览下，感觉有不够强大。&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/ldp615/201112/201112092030418077.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" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201112/201112092030469412.png" width="731" height="301" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201112/20111209203048166.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201112/201112092030532156.png" width="712" height="274" /&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;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TreeNode {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; List&amp;lt;TreeNode&amp;gt; _children;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TreeNode(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; text, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Text = text;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Value = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br/&gt;        _children = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;TreeNode&amp;gt;();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Text { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; Value { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TreeNode Parent { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;TreeNode&amp;gt; Children { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _children; } }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Add(TreeNode childNode) {&lt;br/&gt;        _children.Add(childNode);&lt;br/&gt;        childNode.Parent = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remove(TreeNode childNode) {&lt;br/&gt;        _children.Remove(childNode);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ToString() {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Text;&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;一个比较标准的树节点，有父结点和多个子节点。Value 属性用来保存和树结点相关的对象的值。&lt;/p&gt;&lt;p&gt;再加上一个泛型版本的：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TreeNode&amp;lt;T&amp;gt; : TreeNode {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TreeNode(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; text, T t)&lt;br/&gt;        : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(text, t) {&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; T Value { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (T)&lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.Value; } }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;算是一个强类型的树节点吧。&lt;/p&gt;&lt;p&gt;为了方便树节点的操作，我给 TreeNode 编写了一些扩展方法，如下给出本文要用的一个：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;查找所有叶子节点的扩展方法&lt;/strong&gt;&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TreeNodeExtensions {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;TreeNode&amp;gt; GetLeafNodes(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; TreeNode treeNode) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; child &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; treeNode.Children) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (child.Children.Any()) {&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; descendant &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; GetLeafNodes(child))&lt;br/&gt;                    yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; descendant;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br/&gt;                yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; child;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;一个迭推调用。&lt;/p&gt;&lt;p&gt;最后到了重点：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;TreeBuilder 相关类&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;TreeBuilder 类：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TreeBuilder {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; BuildRootContext Build(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; text) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; root = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TreeNode(text);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BuildRootContext(root);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; TreeNode&amp;lt;T&amp;gt; BuildNode&amp;lt;T&amp;gt;(T t, Func&amp;lt;T, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt; textSelect = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; text = textSelect != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ? textSelect(t) : Convert.ToString(t);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; node = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TreeNode&amp;lt;T&amp;gt;(text, t);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; node;&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;BuildRootContext 类：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; BuildRootContext {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; TreeNode _tree;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; BuildRootContext(TreeNode tree) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._tree = tree;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; BuildChildrenContext&amp;lt;T&amp;gt; SetItems&amp;lt;T&amp;gt;(IEnumerable&amp;lt;T&amp;gt; items) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; items) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; node = TreeBuilder.BuildNode(item);&lt;br/&gt;            _tree.Add(node);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BuildChildrenContext&amp;lt;T&amp;gt;(_tree);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TreeNode Tree { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _tree; } }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;BuildChildrenContext 类：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;&lt;br/&gt;&lt;span&gt;26&lt;/span&gt;&lt;br/&gt;&lt;span&gt;27&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; BuildChildrenContext&amp;lt;T&amp;gt; {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; TreeNode _tree;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; BuildChildrenContext(TreeNode tree) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._tree = tree;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TreeNode Tree { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _tree; } }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; BuildChildrenContext&amp;lt;V&amp;gt; SetItems&amp;lt;V&amp;gt;(Func&amp;lt;T, IEnumerable&amp;lt;V&amp;gt;&amp;gt; itemSelector, Func&amp;lt;V, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt; textSelect = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; leafNodes = _tree.GetLeafNodes().OfType&amp;lt;TreeNode&amp;lt;T&amp;gt;&amp;gt;();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; leafNode &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; leafNodes) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; child &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; itemSelector(leafNode.Value)) {&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; node = TreeBuilder.BuildNode(child, textSelect);&lt;br/&gt;                leafNode.Add(node);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BuildChildrenContext&amp;lt;V&amp;gt;(_tree);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; BuildChildrenContext&amp;lt;T&amp;gt; SetRecursiveItems(Func&amp;lt;T, IEnumerable&amp;lt;T&amp;gt;&amp;gt; itemSelector,&lt;br/&gt;        Func&amp;lt;T, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt; textSelect = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; context = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;while&lt;/span&gt; (_tree.GetLeafNodes().OfType&amp;lt;TreeNode&amp;lt;T&amp;gt;&amp;gt;().Any(n =&amp;gt; itemSelector(n.Value).Any()))&lt;br/&gt;            context = context.SetItems&amp;lt;T&amp;gt;(itemSelector, textSelect);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; context;&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&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;&lt;strong&gt;有限级树&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;像第一张图片中的产品树，只有两级：类别和产品，使用如下代码创建：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; tree = TreeBuilder.Build(&amp;quot;&lt;span style="color: #8b0000"&gt;产品&lt;/span&gt;&amp;quot;)&lt;br/&gt;    .SetItems(categories)&lt;br/&gt;    .SetItems(category =&amp;gt; products.Where(p =&amp;gt; p.Category == category))&lt;br/&gt;    .Tree;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;第 1 行，构建根结点，传入一个字符串作为根结点的文本。&lt;/p&gt;&lt;p&gt;第 2 行，指定树的第一级，必须传入一个集合，上面传入的是 IEnumerable&amp;lt;Category&amp;gt;。&lt;/p&gt;&lt;p&gt;第 3 行，指定树的第二级，传入的是 Func&amp;lt;Category, IEnumerable&amp;lt;Product&amp;gt;&amp;gt;。&lt;/p&gt;&lt;p&gt;第 4 行，调用 Tree 属性，返回根结点，也是树了。&lt;/p&gt;&lt;p&gt;如果需要更多的级数，可将代码写在调用 Tree属性之前，也就是第 3 行和第 4 行之间。&lt;/p&gt;&lt;p&gt;增加一级，可以写成下面的样子（可没什么实际意义）：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; tree = TreeBuilder.Build(&amp;quot;&lt;span style="color: #8b0000"&gt;产品&lt;/span&gt;&amp;quot;)&lt;br/&gt;    .SetItems(categories)&lt;br/&gt;    .SetItems(category =&amp;gt; products.Where(p =&amp;gt; p.Category == category))&lt;br/&gt;    .SetItems(product=&amp;gt;product.Name)&lt;br/&gt;    .Tree;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;无限级树&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;第二张图片中的员工树是无限级的，因为员工的下属还可能有下属，是没有限制级数的。使用 SetRecursiveItems 方法构建：&lt;/p&gt;&lt;p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; tree = TreeBuilder.Build(&amp;quot;&lt;span style="color: #8b0000"&gt;员工树&lt;/span&gt;&amp;quot;)&lt;br/&gt;    .SetItems(employees.Where(e =&amp;gt; e.ReportsTo == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;))&lt;br/&gt;    .SetRecursiveItems(e =&amp;gt; e.Subordinates)&lt;br/&gt;    .Tree;        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;其代码它部分和有限级树相同。&lt;/p&gt;&lt;p&gt;还可以在员工树增加层次，之上增加部门，之后增加爱好等等，调用 SetItmes 即可。&lt;/p&gt;&lt;p&gt;部门无限然后员工无限，也是可以的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通过 TreeBuilder 可以让我们极其方便的创建很复杂的树，让我们把更多的精力放在业务逻辑上（而不是程序或界面逻辑）。&lt;/p&gt;&lt;p&gt;文中代码编写仓促，如有 Bug 请在回复中告知。&lt;/p&gt;&lt;p&gt;如果本文对你有帮助或启发，不妨推荐一下让更多的朋友看到。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;在线演示：&lt;/p&gt;&lt;p&gt;你可以通过下面两个网址，看到通过本文的代码生成的树：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://demo.highsoft.cc/products/tree" target="_blank"&gt;产品树&lt;/a&gt;：&lt;a href="http://demo.highsoft.cc/products/tree" target="_blank"&gt;http://demo.highsoft.cc/products/tree&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;&lt;a href="http://demo.highsoft.cc/employees/multi-select-tree" target="_blank"&gt;员工树&lt;/a&gt;：&lt;a href="http://demo.highsoft.cc/employees/multi-select-tree" target="_blank"&gt;http://demo.highsoft.cc/employees/multi-select-tree&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;源码下载：&lt;a id="" href="http://files.cnblogs.com/ldp615/TreeDemo.rar"&gt;TreeDemo.rar&lt;/a&gt; （15KB）&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2282681.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/09/simple-create-a-complex-tree.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/12/05/asp-net-mvc-elegant-route.html</id><title type="text">ASP.NET MVC：自定义 Route 让你的 Url 更优雅</title><summary type="text">如今，互联网越来越注重简单优雅的 Url, 相信大多朋友都喜欢小写、使用负号作为连字符的 url。本文使用自定义 Route 来实现，只需增加几个类和简单修改下 global.asax 文件。</summary><published>2011-12-05T12:11:00Z</published><updated>2011-12-05T12:11:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/12/05/asp-net-mvc-elegant-route.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/12/05/asp-net-mvc-elegant-route.html"/><content type="html">&lt;p&gt;如今，互联网越来越注重简单优雅的 Url，对比下面两个：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="http://demo.highsoft.cc/products/update-unit-price/5" href="http://demo.highsoft.cc/Products/UpdateUnitPrice/5"&gt;~/Products/UpdateUnitPrice/5&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="http://demo.highsoft.cc/products/update-unit-price/5" href="http://demo.highsoft.cc/products/update-unit-price/5"&gt;~/products/update-unit-price/5&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;我相信大多数朋友会更喜欢第二种方式：小写，使用负（减）号作为连字符。&lt;/p&gt;  &lt;p&gt;本文使用自定义 Route 来达到方式二的效果，只需增加几个类和简单修改下 global.asax 文件。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Route 是双向的&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Route 的基本概念我就不多说了，这里重点强调一下 ASP.NET MVC 中 Route 是双向的，这可以从 RouteBase 类的定义可以看出：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RouteBase{&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; RouteData GetRouteData(HttpContextBase httpContext);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;GetRouteData 用于解析 Url，GetVirtualPath 用于生成 Url。&lt;/p&gt;&lt;p&gt;在开始编写我们的 Route 类之前，我们需要一个用于处理字符串的静态类：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;StringElegantHelper 类&lt;/strong&gt;&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;&lt;br/&gt;&lt;span&gt;26&lt;/span&gt;&lt;br/&gt;&lt;span&gt;27&lt;/span&gt;&lt;br/&gt;&lt;span&gt;28&lt;/span&gt;&lt;br/&gt;&lt;span&gt;29&lt;/span&gt;&lt;br/&gt;&lt;span&gt;30&lt;/span&gt;&lt;br/&gt;&lt;span&gt;31&lt;/span&gt;&lt;br/&gt;&lt;span&gt;32&lt;/span&gt;&lt;br/&gt;&lt;span&gt;33&lt;/span&gt;&lt;br/&gt;&lt;span&gt;34&lt;/span&gt;&lt;br/&gt;&lt;span&gt;35&lt;/span&gt;&lt;br/&gt;&lt;span&gt;36&lt;/span&gt;&lt;br/&gt;&lt;span&gt;37&lt;/span&gt;&lt;br/&gt;&lt;span&gt;38&lt;/span&gt;&lt;br/&gt;&lt;span&gt;39&lt;/span&gt;&lt;br/&gt;&lt;span&gt;40&lt;/span&gt;&lt;br/&gt;&lt;span&gt;41&lt;/span&gt;&lt;br/&gt;&lt;span&gt;42&lt;/span&gt;&lt;br/&gt;&lt;span&gt;43&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; StringElegantHelper {&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;char&lt;/span&gt; minus = '-';&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Elegant(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; s) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; builder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; index = 0;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; c &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; s) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (c &amp;gt;= 'A' &amp;amp;&amp;amp; c &amp;lt;= 'Z') {&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (index &amp;gt; 0) builder.Append(minus);&lt;br/&gt;                builder.Append(&lt;span style="color: #0000ff"&gt;char&lt;/span&gt;.ToLower(c));&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (c == minus) {&lt;br/&gt;                builder.Append(minus);&lt;br/&gt;                builder.Append(minus);&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br/&gt;                builder.Append(c);&lt;br/&gt;            index++;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; builder.ToString();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; DeElegant(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; s) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; builder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; iterator = s.GetEnumerator();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;while&lt;/span&gt; (iterator.MoveNext()) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (iterator.Current != minus) {&lt;br/&gt;                builder.Append(iterator.Current);&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!iterator.MoveNext()) {&lt;br/&gt;                builder.Append(minus);&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (iterator.Current == minus)&lt;br/&gt;                builder.Append(minus);&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br/&gt;                builder.Append(iterator.Current);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; builder.ToString();&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;StringElegantHelper 中有两个方法 Elegant 和 DeElegant，将分别用在 GetVirtualPath 和 GetRouteData 方法中，用于生成和解析优雅的 Url。&lt;/p&gt;&lt;p&gt;这两方法也可以使用正则表达式来实现，但我认为效率不高，就采用了上面这种最朴实的方式。&lt;/p&gt;&lt;p&gt;有了 StringElegantHelper 类，写出 ElegantRoute 就简单多了：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ElegantRoute 类&lt;/strong&gt;&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;&lt;br/&gt;&lt;span&gt;26&lt;/span&gt;&lt;br/&gt;&lt;span&gt;27&lt;/span&gt;&lt;br/&gt;&lt;span&gt;28&lt;/span&gt;&lt;br/&gt;&lt;span&gt;29&lt;/span&gt;&lt;br/&gt;&lt;span&gt;30&lt;/span&gt;&lt;br/&gt;&lt;span&gt;31&lt;/span&gt;&lt;br/&gt;&lt;span&gt;32&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ElegantRoute : Route {&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] ToElegant =  &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; [] { &amp;quot;&lt;span style="color: #8b0000"&gt;controller&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color: #8b0000"&gt;action&lt;/span&gt;&amp;quot; };&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ElegantRoute(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)&lt;br/&gt;        : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(url, defaults, constraints, dataTokens, routeHandler) { }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; RouteData GetRouteData(HttpContextBase httpContext) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; result = &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.GetRouteData(httpContext);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (result == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; key &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; ToElegant)&lt;br/&gt;            HandleItem(result.Values, key, StringElegantHelper.DeElegant);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; result;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; elegantValues = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(values);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; key &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; ToElegant)&lt;br/&gt;            HandleItem(elegantValues, key, StringElegantHelper.Elegant);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.GetVirtualPath(requestContext, elegantValues);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HandleItem(RouteValueDictionary dict, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; key, Func&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt; handler) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!dict.ContainsKey(key)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = dict[key];&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!(&lt;span style="color: #0000ff"&gt;value&lt;/span&gt; &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br/&gt;        dict[key] = handler(&lt;span style="color: #0000ff"&gt;value&lt;/span&gt; &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;注意，上面代码中只对 controller 和 action 的路由值进行了“优雅”处理，其它值并没有，为什么呢？&lt;/p&gt;&lt;p&gt;大家可以考虑以下网址：&lt;/p&gt;&lt;p&gt;&lt;a href="http://demo.highsoft.cc/customers/details/ANTON"&gt;~/customers/details/ANTON&lt;/a&gt;&lt;/p&gt;&lt;p&gt;全部处理的话会变成：&lt;/p&gt;&lt;p&gt;&lt;a href="http://demo.highsoft.cc/customers/details/ANTON"&gt;~/customers/details/a-n-t-o-n&lt;/a&gt;&lt;/p&gt;&lt;p&gt;代码其他部分比较简单，不多说了。&lt;/p&gt;&lt;p&gt;最后，还需要几个扩展方法，以方便在 global.asax 文件中使用：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ElegantRouteExtensions 类&lt;/strong&gt;&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ElegantRouteExtensions {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ElegantRoute MapElegantRoute(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; RouteCollection routes, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; url, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; defaults) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; route = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ElegantRoute(url,&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(defaults),&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(), &lt;span style="color: #008000"&gt;//constraints&lt;/span&gt;&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(), &lt;span style="color: #008000"&gt;//dataTokens&lt;/span&gt;&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MvcRouteHandler());&lt;br/&gt;        routes.Add(name, route);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; route;&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;我只写出一个，大家可根据需要添加。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用 ElegantRouter&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;借助上面的扩展方法，使用就很相当简单了。&lt;/p&gt;&lt;p&gt;global.asax 文件中，把 routes.MapRoute 替换为 routes.MapElegantRoute 即可：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        routes.MapElegantRoute(  &lt;span style="color: #008000"&gt;// MapRoute&lt;/span&gt;&lt;br/&gt;    &amp;quot;&lt;span style="color: #8b0000"&gt;Default&lt;/span&gt;&amp;quot;, &lt;br/&gt;    &amp;quot;&lt;span style="color: #8b0000"&gt;{controller}/{action}/{id}&lt;/span&gt;&amp;quot;, &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; { controller = &amp;quot;&lt;span style="color: #8b0000"&gt;Home&lt;/span&gt;&amp;quot;, action = &amp;quot;&lt;span style="color: #8b0000"&gt;Index&lt;/span&gt;&amp;quot;, id = UrlParameter.Optional } &lt;br/&gt;);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;运行起来验证，点下右上角的 [ Log On ]&amp;#160; 链接：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201112/201112051949133410.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" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201112/201112051949158752.png" width="639" height="524" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;ElegantRoute 生成和解析通过。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;font color="#c0504d"&gt;本文代码未严格测试，如有 bug，请在回复中告知，不胜感激！&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;源码下载：&lt;a href="http://files.cnblogs.com/ldp615/ElegantRouteDemo.rar"&gt;ElegantRouteDemo.rar&lt;/a&gt; （75KB）&lt;/p&gt;&lt;p&gt;在线演示：&lt;a href="http://demo.highsoft.cc/products"&gt;http://demo.highsoft.cc/products&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2277167.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/12/05/asp-net-mvc-elegant-route.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/10/07/can-you-find-the-error-in-foreach-extension-method.html</id><title type="text">你能指出这个 ForEach 扩展方法中的错误吗？</title><summary type="text">Linq 中没有原生的 ForEach 扩展方法，我们可以很轻松的扩展一个......但这个有返回值的实现中有错误的，你能指出吗？</summary><published>2011-10-07T08:06:00Z</published><updated>2011-10-07T08:06:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/10/07/can-you-find-the-error-in-foreach-extension-method.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/10/07/can-you-find-the-error-in-foreach-extension-method.html"/><content type="html">&lt;p&gt;&lt;strong&gt;带返回值的 ForEach 扩展&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Linq 中没有原生的 ForEach 扩展方法，我们可以很轻松的扩展一个：    &lt;table class="code-table"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td class="number"&gt;           &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; void ForEach&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, Action&amp;lt;T&amp;gt; action) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; element &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; source) action(element);&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;上面这个 ForEach 是没有返回值的，写完 ForEach 本句代码也就结束了，这与 Linq 链式编程风格是不符的。&lt;/p&gt;&lt;p&gt;细心查看的话，你会发现 Enumerble 和 Queryable 中的每个扩展方法都是有返回值的，这样才能保证代码链链不断。&lt;/p&gt;&lt;p&gt;改进下，让 ForEach 返回 IEnumerable&amp;lt;T&amp;gt;，相信不少朋友会&lt;font color="#ff0000"&gt;错误&lt;/font&gt;地写出如下的代码：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;em&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; ForEach&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, Action&amp;lt;T&amp;gt; action) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; element &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; source) action(element);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; source;&lt;br/&gt;}&lt;/strong&gt;&lt;/em&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;园子里中就有这么一篇文章是这样实现的，文章还被选入了博客文库。&lt;strong&gt;你能胜过小编，指出其中的错误吗。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;通过单元测试查找错误&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们来测试下这个扩展方法，先写第一个测试：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Employee {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; Bonus { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;}&lt;br/&gt;[TestMethod()]&lt;br/&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ForEachTest() {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee[] {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee{ Name = &amp;quot;&lt;span style="color: #8b0000"&gt;张三&lt;/span&gt;&amp;quot;, Bonus =  500 },&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee { Name = &amp;quot;&lt;span style="color: #8b0000"&gt;李四&lt;/span&gt;&amp;quot;, Bonus =  800}&lt;br/&gt;    };&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; actualBonus = employees&lt;br/&gt;        .ForEach(e =&amp;gt; e.Bonus += 200)&lt;br/&gt;        .First(e =&amp;gt; e.Name == &amp;quot;&lt;span style="color: #8b0000"&gt;李四&lt;/span&gt;&amp;quot;)&lt;br/&gt;        .Bonus;&lt;br/&gt;    Assert.AreEqual(1000, actualBonus);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;span id="xn155_da687de0bb2149c30a99b2da21328ada" class="sentence"&gt;说明：在 .NET Framework 2.0 版中，&lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;span class="selflink"&gt;Array&lt;/span&gt;&lt;/span&gt; 类实现 &lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/5y536ey6.aspx"&gt;System.Collections.Generic&lt;span xmlns="xmlns"&gt;.&lt;/span&gt;IList&lt;span xmlns="xmlns"&gt;&amp;lt;&lt;/span&gt;T&lt;span xmlns="xmlns"&gt;&amp;gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;、&lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/92t2ye13.aspx"&gt;System.Collections.Generic&lt;span xmlns="xmlns"&gt;.&lt;/span&gt;ICollection&lt;span xmlns="xmlns"&gt;&amp;lt;&lt;/span&gt;T&lt;span xmlns="xmlns"&gt;&amp;gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; 和 &lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/9eekhta0.aspx"&gt;System.Collections.Generic&lt;span xmlns="xmlns"&gt;.&lt;/span&gt;IEnumerable&lt;span xmlns="xmlns"&gt;&amp;lt;&lt;/span&gt;T&lt;span xmlns="xmlns"&gt;&amp;gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; 泛型接口。&lt;/span&gt; &lt;span id="xn156_9a4db72ac65d69d5eff2307b61a00f54" class="sentence"&gt;由于实现是在运行时提供给数组的，因而对于文档生成工具不可见。&lt;/span&gt; &lt;span id="xn157_61ded6dd87fc54019fbe0a06aa5f542b" class="sentence"&gt;因此，泛型接口不会出现在 &lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;span class="selflink"&gt;Array&lt;/span&gt;&lt;/span&gt; 类的声明语法中，也不会有关于只能通过将数组强制转换为泛型接口类型（显式接口实现）才可访问的接口成员的参考主题。&lt;/span&gt; &lt;span id="xn158_bdac9e043f1b6939a70352bb806e803b" class="sentence"&gt;将某一数组强制转换为这三种接口之一时需要注意的关键一点是，添加、插入或移除元素的成员会引发 &lt;span xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/system.notsupportedexception.aspx"&gt;NotSupportedException&lt;/a&gt;&lt;/span&gt;。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;摘自：&lt;a href="http://msdn.microsoft.com/zh-cn/library/system.array.aspx"&gt;http://msdn.microsoft.com/zh-cn/library/system.array.aspx&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;这个测试是可以顺利通过的，但不能说明代码是正确的，我们再来写一个测试。&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/system.linq.enumerable.range.aspx"&gt;Enumerable.Range 方法&lt;/a&gt; 可以生成整数序列，我们就调用它来作为 source 参数：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        [TestMethod()]&lt;br/&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ForEachTest2() {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; nums = Enumerable.Range(1, 10);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; actual = nums.ForEach(i =&amp;gt; i *= 10).First();&lt;br/&gt;    Assert.AreEqual(10, actual);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;第 4 行仅为了测试，其它情况下使用 Select(i =&amp;gt; i*10) 更为恰当。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;这次测试通不过了：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201110/201110071535223767.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/ldp615/201110/20111007153523570.png" width="588" height="99" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;应该思考下了，自已动脑解决 胜过 他人直接告知 。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201110/20111007154840963.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/ldp615/201110/201110071548492024.png" width="571" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;再给出最后一个测试，看了基本就能找出错误所在了：   &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Employee&amp;gt; GetEmployees() {&lt;br/&gt;    yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee {Name = &amp;quot;&lt;span style="color: #8b0000"&gt;张三&lt;/span&gt;&amp;quot;, Bonus = 500};&lt;br/&gt;    yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee {Name = &amp;quot;&lt;span style="color: #8b0000"&gt;李四&lt;/span&gt;&amp;quot;, Bonus = 800};&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;[TestMethod()]&lt;br/&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ForEachTest3() {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = GetEmployees();&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; actualBonus = employees&lt;br/&gt;        .ForEach(e =&amp;gt; e.Bonus += 200)&lt;br/&gt;        .First(e =&amp;gt; e.Name == &amp;quot;&lt;span style="color: #8b0000"&gt;李四&lt;/span&gt;&amp;quot;)&lt;br/&gt;        .Bonus;&lt;br/&gt;    Assert.AreEqual(1000, actualBonus);&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;问题所在&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通过上面几个测试，应该发现 &lt;a href="http://msdn.microsoft.com/zh-cn/library/9k7k7cf0(v=VS.80).aspx"&gt;yield&lt;/a&gt; 的特性会让上面的 ForEach 出问题，请参看 Artech 的文章 《 &lt;a href="http://www.cnblogs.com/artech/archive/2010/10/28/yield.html" target="_blank"&gt;从yield关键字看IEnumerable和Collection的区别&lt;/a&gt; 》进行更深入的了解。&lt;/p&gt;&lt;p&gt;如果你使用的是 IQueryable&amp;lt;T&amp;gt; 问题可能出现，要考虑一些 ORM 框架的缓存情况。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;正确实现&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;那么怎么正确实现 ForEach 扩展方法呢，我想还是留给大家来思考完成吧，一味接受可不是好的学习方式。&lt;/p&gt;&lt;p&gt;另外，还可以实现如下签名的扩展，以方便使用：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; ForEach&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, Action&amp;lt;T, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt; action) {&lt;span style="color: #008000"&gt;/*...*/&lt;/span&gt; }      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;有关 Linq 中为什么没有原生的的 ForEach 扩展的讨论，请参见文章：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/kirillosenkov/archive/2009/01/31/foreach.aspx" target="_blank"&gt;ForEach&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/ericwhite/archive/2009/04/08/why-i-don-t-use-the-foreach-extension-method.aspx"&gt;Why I Don't Use the ForEach Extension Method&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;&lt;a href="http://stackoverflow.com/questions/101265/why-is-there-not-a-foreach-extension-method-on-the-ienumerable-interface" target="_blank"&gt;Why is there not a ForEach extension method on the IEnumerable interface?&lt;/a&gt;&amp;#160; &lt;/li&gt;  &lt;li&gt;&lt;a href="http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/2dddb3b1-5ea3-41a6-880a-f994acf0a68b/" target="_blank"&gt;Suggestion - Enumerable.ForEach&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2200600.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/10/07/can-you-find-the-error-in-foreach-extension-method.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/09/21/reuse-entity-framework-english-pluralization-service.html</id><title type="text">复用 Entity Framework 中英语单复数形式变换的类</title><summary type="text">数据库表名用复数、实体类名用单数，集合属性用单数…编程中经常会遇到英语单复变换的问题，你能准确处理吗？对我来说，十年前或许可以，but don't worry，我们有现成的类提供些类服务，来自 EntityFrameWork。</summary><published>2011-09-21T13:24:00Z</published><updated>2011-09-21T13:24:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/09/21/reuse-entity-framework-english-pluralization-service.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/09/21/reuse-entity-framework-english-pluralization-service.html"/><content type="html">&lt;p&gt;数据库表名用复数、实体类名用单数，集合属性用复数…编程中经常会遇到英语单复数变换的问题，你能准确处理吗？对我来说，十年前或许可以，but don't worry，我们有现成的类提供些类服务，来自 EntityFrameWork。&lt;/p&gt;  &lt;p&gt;使用 &lt;a href="http://wiki.sharpdevelop.net/ilspy.ashx" target="_blank"&gt;ILSpy&lt;/a&gt; 打开 EntityFramework.dll（v4.1），处理单复数的相关类位于 System.Data.Entity.ModelConfiguration.Design.PluralizationServices 命名空间下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109212113452628.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/ldp615/201109/201109212113469115.png" width="506" height="204" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;其中 PluralizationService 是单复数变换服务的抽象基类，定义如下：    &lt;table class="code-table"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td class="number"&gt;           &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PluralizationService {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; CultureInfo Culture {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsPlural(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; word);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsSingular(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; word);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Pluralize(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; word);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Singularize(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; word);&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;///   Factory method for PluralizationService. Only support english pluralization.&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;///   Please set the PluralizationService on the System.Data.Entity.Design.EntityModelSchemaGenerator&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;///   to extend the service to other locales.&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;param name=&amp;quot;culture&amp;quot;&amp;gt;CultureInfo&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;returns&amp;gt;PluralizationService&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; PluralizationService CreateService(CultureInfo culture) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (culture.TwoLetterISOLanguageName == &amp;quot;&lt;span style="color: #8b0000"&gt;en&lt;/span&gt;&amp;quot;) {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EnglishPluralizationService();&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NotImplementedException(&amp;quot;&lt;span style="color: #8b0000"&gt;We don't support locales other than english yet&lt;/span&gt;&amp;quot;);&lt;br/&gt;    }&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;EnglishPluralizationService 是英文的具体实现类，包含了规则变换和不规则变换，代码太长就不贴出了。&lt;/p&gt; &lt;p&gt;估计很多朋友会和我一样会，担心这个实现是否完整。我简单查看了下源码，发现了这个单词：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;strong&gt;&lt;font size="3"&gt;pneumonoultramicroscopicsilicovolcanoconiosis&lt;/font&gt;&lt;/strong&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;不用数了，一共是 45 个字母，这可是最长的英语单词。这么长（估计实际用的也不多）的单词都收录了，再加上 EnglishPluralizationService 类 2451 行的代码，想必非常完整了。&lt;/p&gt;&lt;p&gt;但不幸的是，这些类都是 internal，没法直接用。不过我们可以使用 &lt;a href="http://wiki.sharpdevelop.net/ilspy.ashx"&gt;ILSpy&lt;/a&gt; 把这几个类提出来，供我们享用。&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.sharpdevelop.net/ilspy.ashx"&gt;ILSpy&lt;/a&gt; 可以将整个 dll 反编译成项目，也可以将单个类反编译成文件：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109212113488394.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/ldp615/201109/201109212113549685.png" width="405" height="290" /&gt;&lt;/a&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109212113562585.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/ldp615/201109/201109212114009058.png" width="405" height="291" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;但不能直接反编译一个命名空间，有点遗憾。&lt;/p&gt;&lt;p&gt;余下的工作的和怎么用，就不用我多说了吧。&lt;/p&gt;&lt;p&gt;分享一份我处理好的源码：&lt;a href="http://files.cnblogs.com/ldp615/PluralizationServices.rar"&gt;PluralizationServices.rar&lt;/a&gt;&amp;#160;&lt;font color="#666666"&gt;（8KB，VS2010）&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2184454.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/21/reuse-entity-framework-english-pluralization-service.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/09/18/asp-net-mvc-expression-trees-as-action-parameter-part2.html</id><title type="text">ASP.NET MVC：Expression Trees 作为参数简化查询 二</title><summary type="text">Expression Trees 可用作 Action 的参数来简化查询，前文中给出的 QueryConditionExpressionModelBinder 类，比较僵化，无法满足实际要求。本文将会从这个类为起点，基于 Convention 构建一个灵活的解决方案。</summary><published>2011-09-18T09:25:00Z</published><updated>2011-09-18T09:25:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/09/18/asp-net-mvc-expression-trees-as-action-parameter-part2.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/09/18/asp-net-mvc-expression-trees-as-action-parameter-part2.html"/><content type="html">&lt;p&gt;前文&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/16/asp-net-mvc-expression-trees-as-action-parameter.html"&gt;《ASP.NET MVC：Expression Trees 作为参数简化查询》&lt;/a&gt;中提出可以将 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 用作查询 Action 的参数来简化编码：&lt;/p&gt;  &lt;p&gt;   &lt;table class="code-table"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td class="number"&gt;           &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index([QueryConditionBinder]Expression&amp;lt;Func&amp;lt;Employee, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; predicate) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = repository.Query().Where(predicate);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&amp;quot;&lt;span style="color: #8b0000"&gt;Index&lt;/span&gt;&amp;quot;, employees);&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;文中给出的 QueryConditionExpressionModelBinder 类，比较僵化，无法满足实际要求。本文将会从这个类为起点，构建一个灵活的解决方案。&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://demos.ldp.me/employees"&gt;http://demos.ldp.me/employees&lt;/a&gt;&lt;/p&gt;&lt;p&gt;下图显示的 Expression 是根据查询条件动态生成的：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308227586.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; margin: 0px; padding-top: 0px; border-right-width: 0px" height="751" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308248864.png" width="688" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;调试截图：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308255931.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; margin: 0px; padding-top: 0px; border-right-width: 0px" height="114" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308262998.png" width="783" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;设计目标&lt;/strong&gt;&lt;/p&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;li&gt;比较查询：大于、大于等于、小于、小于等于； &lt;/li&gt;  &lt;li&gt;… &lt;/li&gt;  &lt;li&gt;正确处理可空类型 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;阻止某些查询：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;ID查询 &lt;/li&gt;  &lt;li&gt;某些保密属性，如内部价格属性等 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;扩展性：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;系统容易扩展，开放支持加入新的查询类型 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;易用性：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;简单使用 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;其它：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;查询数据验证，配合 MVC 相应机制，对错误输入给出提示。 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;思考&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;想法源自 Entity Framework：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;EF 中的 Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在 EF Code First 中，Entity 与 数据库 Table 之间映射采用 Convention (约定) 的方式：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg679332(v=VS.103).aspx"&gt;PluralizingTableNameConvention&lt;/a&gt;：实体使用单数形式，自动对应数据库中复数形式的表名； &lt;/li&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg696567(v=VS.103).aspx"&gt;IdKeyDiscoveryConvention&lt;/a&gt;：自动找寻主键，名为 Id 或 Entity 类名 + Id 的属性自动认为是主键； &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;a href="http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions(v=VS.103).aspx"&gt;System.Data.Entity.ModelConfiguration.Conventions&lt;/a&gt; 命名空间中有很多这样的 Convention。这些 Convention 都是被大多人公认的，EF 运行时会加载这些 Convention，因此我们使用 EF 会相当简单，不需要像 NH 那样进行大量繁琐无聊的映射配置工作。&lt;/p&gt;&lt;p&gt;如果你认可其中的某条 Convention 你可以将它移除：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; NorthwindDbContext : DbContext&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder) {&lt;br/&gt;        modelBuilder.Conventions.Remove&amp;lt;IdKeyDiscoveryConvention&amp;gt;();&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;不错吧，但 EF 不允许添加新的 Convention，有点遗憾。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;分解出 Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;借鉴 EF 的思路，我们可以分解出以下 Convention：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;ValueTypeEqualsConvention：值类型相等，年龄 == 18、婚否 = false； &lt;/li&gt;  &lt;li&gt;StringContainsConvention：字符串包含，即模糊查询； &lt;/li&gt;  &lt;li&gt;DateEqualsConvention：日期等于，忽略时间； &lt;/li&gt;  &lt;li&gt;ValueTypeCompareConvention：值类型比较，价格大于 12.00； &lt;/li&gt;  &lt;li&gt;BetweenDatesConvention：时间界于两个日期之间； &lt;/li&gt;  &lt;li&gt;IDForbiddenConvention：禁止对 ID 查询。 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;还有一点，要将各个条件组合起来，如：(年龄 &amp;lt;= 18) 并且 (婚否 = false)， 或者 (年龄 &amp;lt;= 18) 或者 (婚否 = false)。因此，还要定义用于连接组合的 Convention：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;AndCombineConvention：并且，在页面查询中，这个比较常用，我们设成默认的； &lt;/li&gt;  &lt;li&gt;OrCombinedConvention：或者； &lt;/li&gt;  &lt;li&gt;XXXComplexCombineConvention：更加复杂的情况，如：(存款 &amp;gt; 100,000,000) Or ((年龄 &amp;lt;= 18) 并且 (婚否 = false))。 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;可设置的 Order 属性&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;给每个 Convention 设置一个优先顺序号，大的优先级高：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;StringContainsConvention、DateEqualsConvention 优先于 ValueTypeEqualsConvention； &lt;/li&gt;  &lt;li&gt;BetweenDatesConvention 优先于 DateEqualsConvention。 &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;即采用了 StringContainsConvention 就不会再采用 ValueTypeEqualsConvention。&lt;/p&gt;&lt;p&gt;编码时会根据实际应用给每个 Convention 设置一个默认的合理的 Order 值，但为了灵活通用，允许修改，Order 是一个 get-set 属性。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;可以添加新的 Convention 以满足更多应用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;EF 只能移除不能添加，有时感不方便，不太符合 OCP（Open-Closed principle）。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;编码实现&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;抽象出接口&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;根据上面的分析，可以提取出下面三个接口：&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;    &lt;p&gt;IConvention 接口，代表所有的约定：&lt;/p&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IConvention {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Order { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;  &lt;li&gt;    &lt;p&gt;IPropertyExpressionConvention 接口，将单个查询条件转换为 Expression：&lt;/p&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IPropertyExpressionConvention: IConvention {&lt;br/&gt;    Expression BuildExpression(BuildPropertyExpressionContext context);&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;  &lt;li&gt;    &lt;p&gt;IExpressionCombineConvention 接口，将多个查询 Expression 进行合并：&lt;/p&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IExpressionCombineConvention : IConvention {&lt;br/&gt;    Expression Combine(IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, Expression&amp;gt; expressions);&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;修改 QueryConditionExpressionModelBinder 类&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;修改后代码如下：   &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;&lt;br/&gt;&lt;span&gt;26&lt;/span&gt;&lt;br/&gt;&lt;span&gt;27&lt;/span&gt;&lt;br/&gt;&lt;span&gt;28&lt;/span&gt;&lt;br/&gt;&lt;span&gt;29&lt;/span&gt;&lt;br/&gt;&lt;span&gt;30&lt;/span&gt;&lt;br/&gt;&lt;span&gt;31&lt;/span&gt;&lt;br/&gt;&lt;span&gt;32&lt;/span&gt;&lt;br/&gt;&lt;span&gt;33&lt;/span&gt;&lt;br/&gt;&lt;span&gt;34&lt;/span&gt;&lt;br/&gt;&lt;span&gt;35&lt;/span&gt;&lt;br/&gt;&lt;span&gt;36&lt;/span&gt;&lt;br/&gt;&lt;span&gt;37&lt;/span&gt;&lt;br/&gt;&lt;span&gt;38&lt;/span&gt;&lt;br/&gt;&lt;span&gt;39&lt;/span&gt;&lt;br/&gt;&lt;span&gt;40&lt;/span&gt;&lt;br/&gt;&lt;span&gt;41&lt;/span&gt;&lt;br/&gt;&lt;span&gt;42&lt;/span&gt;&lt;br/&gt;&lt;span&gt;43&lt;/span&gt;&lt;br/&gt;&lt;span&gt;44&lt;/span&gt;&lt;br/&gt;&lt;span&gt;45&lt;/span&gt;&lt;br/&gt;&lt;span&gt;46&lt;/span&gt;&lt;br/&gt;&lt;span&gt;47&lt;/span&gt;&lt;br/&gt;&lt;span&gt;48&lt;/span&gt;&lt;br/&gt;&lt;span&gt;49&lt;/span&gt;&lt;br/&gt;&lt;span&gt;50&lt;/span&gt;&lt;br/&gt;&lt;span&gt;51&lt;/span&gt;&lt;br/&gt;&lt;span&gt;52&lt;/span&gt;&lt;br/&gt;&lt;span&gt;53&lt;/span&gt;&lt;br/&gt;&lt;span&gt;54&lt;/span&gt;&lt;br/&gt;&lt;span&gt;55&lt;/span&gt;&lt;br/&gt;&lt;span&gt;56&lt;/span&gt;&lt;br/&gt;&lt;span&gt;57&lt;/span&gt;&lt;br/&gt;&lt;span&gt;58&lt;/span&gt;&lt;br/&gt;&lt;span&gt;59&lt;/span&gt;&lt;br/&gt;&lt;span&gt;60&lt;/span&gt;&lt;br/&gt;&lt;span&gt;61&lt;/span&gt;&lt;br/&gt;&lt;span&gt;62&lt;/span&gt;&lt;br/&gt;&lt;span&gt;63&lt;/span&gt;&lt;br/&gt;&lt;span&gt;64&lt;/span&gt;&lt;br/&gt;&lt;span&gt;65&lt;/span&gt;&lt;br/&gt;&lt;span&gt;66&lt;/span&gt;&lt;br/&gt;&lt;span&gt;67&lt;/span&gt;&lt;br/&gt;&lt;span&gt;68&lt;/span&gt;&lt;br/&gt;&lt;span&gt;69&lt;/span&gt;&lt;br/&gt;&lt;span&gt;70&lt;/span&gt;&lt;br/&gt;&lt;span&gt;71&lt;/span&gt;&lt;br/&gt;&lt;span&gt;72&lt;/span&gt;&lt;br/&gt;&lt;span&gt;73&lt;/span&gt;&lt;br/&gt;&lt;span&gt;74&lt;/span&gt;&lt;br/&gt;&lt;span&gt;75&lt;/span&gt;&lt;br/&gt;&lt;span&gt;76&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; QueryConditionExpressionModelBinder : IModelBinder {&lt;br/&gt;    &lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; ConventionConfiguration _conventionConfiguration;&lt;/font&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; QueryConditionExpressionModelBinder(&lt;font style="background-color: #ffff00"&gt;ConventionConfiguration conventionConfiguration&lt;/font&gt;) {&lt;br/&gt;        &lt;font style="background-color: #ffff00"&gt;_conventionConfiguration = conventionConfiguration;&lt;/font&gt;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; QueryConditionExpressionModelBinder(): &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;(ConventionConfiguration.Default) { }&lt;/font&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; modelType = GetModelTypeFromExpressionType(bindingContext.ModelType);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (modelType == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; parameter = Expression.Parameter(modelType, modelType.Name[0].ToString().ToLower());&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; dict = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, Expression&amp;gt;();&lt;br/&gt;&lt;strong&gt;&lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;&lt;/strong&gt;&lt;strong&gt;&lt;font size="+0"&gt;        &lt;/font&gt;&lt;/strong&gt;&lt;strong&gt;&lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; propertyExpressionConvertions = _conventionConfiguration.GetConventions&amp;lt;IPropertyExpressionConvention&amp;gt;();&lt;br/&gt;&lt;/font&gt;&lt;/strong&gt;&lt;strong&gt;&lt;font size="+0"&gt;        &lt;/font&gt;&lt;/strong&gt;&lt;strong&gt;&lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; property &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; modelType.GetProperties()){&lt;/font&gt;&lt;br/&gt;&lt;/strong&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;            &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; convention &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; propertyExpressionConvertions) {&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; context = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BuildPropertyExpressionContext(&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;property,&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;bindingContext.ValueProvider,&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;controllerContext.Controller.ViewData.ModelState,&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;parameter.Property(property.Name)&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;);&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; expression = convention.BuildExpression(context);&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(expression != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;){&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;dict.Add(property.Name, expression);&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                    &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;}&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;                &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (context.IsHandled) &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;            &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;}&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;}&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = &lt;span style="color: #0000ff"&gt;default&lt;/span&gt;(Expression);&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; convention &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _conventionConfiguration.GetConventions&amp;lt;IExpressionCombineConvention&amp;gt;())&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;{&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;            &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;body = convention.Combine(dict);&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;            &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (body != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;}&lt;br/&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="+0"&gt;&lt;strong&gt;        &lt;/strong&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;strong&gt;&lt;span style="color: #008000"&gt;//if (body == null) body = Expression.Constant(true);&lt;/span&gt;&lt;/strong&gt;&lt;/font&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; body.ToLambda(parameter);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// 获取 Expression&amp;lt;Func&amp;lt;TXXX, bool&amp;gt;&amp;gt; 中 TXXX 的类型&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Type GetModelTypeFromExpressionType(Type lambdaExpressionType) {&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (lambdaExpressionType.GetGenericTypeDefinition() != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (Expression&amp;lt;&amp;gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; funcType = lambdaExpressionType.GetGenericArguments()[0];&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (funcType.GetGenericTypeDefinition() != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (Func&amp;lt;,&amp;gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; funcTypeArgs = funcType.GetGenericArguments();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (funcTypeArgs[1] != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; funcTypeArgs[0];&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// 获取属性的查询值并处理 Controller.ModelState &lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; GetValueAndHandleModelState(PropertyInfo property, IValueProvider valueProvider, ControllerBase controller) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; result = valueProvider.GetValue(property.Name);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (result == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; modelState = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ModelState {Value = result};&lt;br/&gt;        controller.ViewData.ModelState.Add(property.Name, modelState);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;{&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = result.ConvertTo(property.PropertyType);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception ex){&lt;br/&gt;            modelState.Errors.Add(ex);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;高亮代码为修改或新增部分。&lt;/p&gt;&lt;p&gt;QueryConditionExpressionModelBinder 中使用了 ConventionConfiguration 类：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ConventionConfiguration {&lt;br/&gt;&lt;br/&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ConventionConfiguration Default = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ConventionConfiguration();&lt;br/&gt;&lt;br/&gt;   &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ConventionConfiguration() {&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ValueTypeEqualsConvention());&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringContainsConvention());&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DateEqualsConvention());&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BetweenDatesConvention());&lt;br/&gt;       &lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AwalysTrueCombineConvention());&lt;br/&gt;       Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; OrCombineConvention());&lt;br/&gt;   }&lt;br/&gt;&lt;br/&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ConventionConfiguration() {&lt;br/&gt;       Conventions = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HashSet&amp;lt;IConvention&amp;gt;();&lt;br/&gt;   }&lt;br/&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HashSet&amp;lt;IConvention&amp;gt; Conventions { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;   &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; GetConventions&amp;lt;T&amp;gt;() where T: IConvention {&lt;br/&gt;       &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Conventions&lt;br/&gt;           .OfType&amp;lt;T&amp;gt;()&lt;br/&gt;           .OrderByDescending(c =&amp;gt; c.Order);&lt;br/&gt;   }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;实现具体 Converntion：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;ValueTypeEqualsConvention     &lt;br /&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ValueTypeEqualsConvention : PropertyExpressionConventionBase {&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ValueTypeEqualsConvention():&lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(1) {}&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Expression BuildExpression(BuildPropertyExpressionContext context) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!context.Property.PropertyType.IsValueType) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; queryValue = context.ValueProvider.GetQueryValue(context.Property.Name, context.Property.PropertyType);&lt;br/&gt;        context.ModelState.AddIfValueNotNull(context.Property.Name, queryValue.ModelState);&lt;br/&gt;        context.IsHandled = queryValue.ModelState != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(queryValue.Value == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; context.PropertyExpression.Equal(Expression.Constant(queryValue.Value));&lt;br/&gt;    }&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;  &lt;li&gt;StringContainsConvention     &lt;br /&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; StringContainsConvention : PropertyExpressionConventionBase {&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; StringContainsConvention():&lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(10) { }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Expression BuildExpression(BuildPropertyExpressionContext context) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (context.Property.PropertyType != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; queryValue = context.ValueProvider.GetQueryValue(context.Property.Name, context.Property.PropertyType);&lt;br/&gt;        context.ModelState.AddIfValueNotNull(context.Property.Name, queryValue.ModelState);&lt;br/&gt;        context.IsHandled = queryValue.ModelState != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; ((queryValue.Value &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;).IsNullOrEmpty()) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; context.PropertyExpression.Call(&amp;quot;&lt;span style="color: #8b0000"&gt;Contains&lt;/span&gt;&amp;quot;, Expression.Constant(queryValue.Value));&lt;br/&gt;    }&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;  &lt;li&gt;DateEqualsConvention     &lt;br /&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; DateEqualsConvention: PropertyExpressionConventionBase {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DateEqualsConvention():&lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(10) { }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; System.Linq.Expressions.Expression BuildExpression(BuildPropertyExpressionContext context) {&lt;br/&gt;        &lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (context.Property.PropertyType.NotIn(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(DateTime), &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(DateTime?))) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/font&gt;&lt;br/&gt;        &lt;font style="background-color: #ffff00"&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!context.Property.Name.EndsWith(&amp;quot;&lt;span style="color: #8b0000"&gt;day&lt;/span&gt;&amp;quot;, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;, CultureInfo.CurrentCulture) &amp;amp;&amp;amp;&lt;/font&gt; &lt;br/&gt;            &lt;font style="background-color: #ffff00"&gt;!context.Property.Name.EndsWith(&amp;quot;&lt;span style="color: #8b0000"&gt;date&lt;/span&gt;&amp;quot;, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;, CultureInfo.CurrentCulture)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/font&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; queryValue = context.ValueProvider.GetQueryValue(context.Property.Name, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(DateTime));&lt;br/&gt;        context.ModelState.AddIfValueNotNull(context.Property.Name, queryValue.ModelState);&lt;br/&gt;        context.IsHandled = queryValue.ModelState != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (queryValue.Value == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; date = ((DateTime)queryValue.Value).Date;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; expression = context.PropertyExpression;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (expression.Type == &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(DateTime?)) expression = expression.Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Value&lt;/span&gt;&amp;quot;);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; expression.Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Date&lt;/span&gt;&amp;quot;).Equal(Expression.Constant(date));&lt;br/&gt;    }&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;  &lt;li&gt;AndCombineConvention     &lt;br /&gt;    &lt;table class="code-table"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td class="number"&gt;            &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;          &lt;/td&gt;          &lt;td class="code"&gt;            &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; AndCombineConvention : IExpressionCombineConvention {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Order { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; System.Linq.Expressions.Expression Combine(IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, System.Linq.Expressions.Expression&amp;gt; expressions) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(expressions.Count &amp;gt; 0)&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; expressions.Values.Aggregate((a, e) =&amp;gt; a.OrElse(e));&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;  &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;特别注意下 DateEqualsConvention，只对名称以 day 或 date 结尾（不区分大小）的 DateTime 或 DateTime？属性进行处理，如 Employee.Birthday、Employee.HireDate。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;项目类图&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;目前实现中主要有以下类和接口：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308052738.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; border-right-width: 0px" height="286" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/20110917230811824.png" width="345" border="0" /&gt;&lt;/a&gt;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308125068.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; border-right-width: 0px" height="230" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308134087.png" width="555" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/20110917230814631.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; border-right-width: 0px" height="323" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308151876.png" width="820" border="0" /&gt;&lt;/a&gt;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308164483.png"&gt;&lt;img title="image" style="border-top-width: 0px; padding-right: 0px; display: inline; padding-left: 0px; border-left-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; border-right-width: 0px" height="309" alt="image" src="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109172308195304.png" width="289" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;扩展方法类未列出。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;QueryConditionExpressionModelBinder 使用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;直接使用&lt;/strong&gt;&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index([QueryConditionBinder]Expression&amp;lt;Func&amp;lt;Employee, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; predicate) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = repository.Query().Where(predicate);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&amp;quot;&lt;span style="color: #8b0000"&gt;Index&lt;/span&gt;&amp;quot;, employees);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;或配置后使用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;若你有新创建的 Convention，可以在 Global.asax 文件中 MvcApplication.Application_Start 方法中进行加入配置：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        ConventionConfiguration.Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; YourConvention());      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;如果默认的 Conversions 不满足你的要示，可以移除后重新增加：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        ConventionConfiguration.Default.Conventions.Clear();&lt;br/&gt;ConventionConfiguration.Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ValueTypeEqualsConvention());&lt;br/&gt;ConventionConfiguration.Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DateEqualsConvention { Order = 1000 });&lt;br/&gt;ConventionConfiguration.Default.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; YourConvention{ Order = 2000});      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;因为 Order 属性是可修改的，添加时可以重新指定优先级。&lt;/p&gt;&lt;p&gt;或都你可以给某一个查询单独配置 Convention：   &lt;table class="code-table"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td class="number"&gt;          &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;        &lt;/td&gt;        &lt;td class="code"&gt;          &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; cfg = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ConventionConfiguration();&lt;br/&gt;cfg.Conventions.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringContainsConvention());&lt;br/&gt;ModelBinders.Binders.Add(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Expression&amp;lt;Func&amp;lt;Order, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; QueryConditionExpressionModelBinder(cfg));        &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;这时，就不要再使用 QueryConditionBinderAttribute 了：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; OrdersController : Controller{&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt;  OrdersRepository repository = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; OrdersRepository();&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ViewResult Index(Expression&amp;lt;Func&amp;lt;Order, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; predicate) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; orders = repository.Query().Where(predicate);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(orders);&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;后记&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;根据你的项目，创建适合的 Convention，相信 QueryConditionExpressionModelBinder 一定会帮你省下很多时间。&lt;/p&gt;&lt;p&gt;本文中代码编写仓促，尚未进行严格测试，使用时请注意。如有 bug 请回复给我，谢谢！&lt;/p&gt;&lt;p&gt;后续还有相关文章，实现禁止对某些属性查询的 Convention，以及复杂条件组合 Convention 等等。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;源码下载：&lt;a href="http://files.cnblogs.com/ldp615/MvcQuery2.rar"&gt;MvcQuery2.rar&lt;/a&gt; （1733KB，VS2010 MVC3）&lt;/p&gt;&lt;p&gt;在线演示：&lt;a href="http://demos.ldp.me/employees"&gt;http://demos.ldp.me/employees&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2179975.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/18/asp-net-mvc-expression-trees-as-action-parameter-part2.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/09/16/asp-net-mvc-expression-trees-as-action-parameter.html</id><title type="text">ASP.NET MVC：Expression Trees 作为参数简化查询</title><summary type="text">MVC 引入了 ModelBinder，让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据。在查询 Action 中，我们可以将 Expression Trees 用作参数，通过自定义的 ModelBinder 动态自动构建查询表达式树，进一步发挥 MVC 的威力，简化编码工作。</summary><published>2011-09-16T15:09:00Z</published><updated>2011-09-16T15:09:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/09/16/asp-net-mvc-expression-trees-as-action-parameter.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/09/16/asp-net-mvc-expression-trees-as-action-parameter.html"/><content type="html">&lt;p&gt;&lt;strong&gt;引言&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;ASP.NET MVC 引入了 ModelBinder 技术，让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据，极大的方便了我们的编程，提高了生产力。在查询 Action 中，我们可以将 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 用作参数，通过自定义的 ModelBinder 动态自动构建查询表达式树，进一步发挥 MVC 的威力，简化编码工作。&lt;/p&gt;  &lt;p&gt;先给出本文中使用的 Model：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Employee {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; ID { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; FirstName { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; LastName { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; Sex { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DateTime? Birthday { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Remark { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;MVC 查询和存在的不足&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;下面是一个查询 Employee 的 Action，在 MVC 项目中经常可以见到：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; firstName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; lastName, DateTime? birthday, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;? sex) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = repository.Query();&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (firstName.IsNotNullAndEmpty()) &lt;br/&gt;        employees = employees.Where(e =&amp;gt; e.FirstName.Contains(firstName));&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (firstName.IsNotNullAndEmpty()) &lt;br/&gt;        employees = employees.Where(e =&amp;gt; e.LastName.Contains(lastName));&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (birthday.HasValue) &lt;br/&gt;        employees = employees.Where(e =&amp;gt; e.Birthday.Value.Date == birthday.Value.Date);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (sex.HasValue) &lt;br/&gt;        employees = employees.Where(e =&amp;gt; e.Sex == sex);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(employees);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;得益于 MVC 的绑定技术，我们可以简单通过 Action 的参数来获取请求的值，很少再使用 Request[&amp;quot;XXXX&amp;quot;] 的方式。&lt;/p&gt;&lt;p&gt;仔细观察，会发现上面这个 Action 中充斥着大量 if 判断，以致代码行数比较多，不是特别清晰。可以借助本人&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/17/WhereIf-ExtensionMethod.html"&gt;《c# 扩展方法奇思妙用基础篇 六：WhereIf 扩展》&lt;/a&gt;一文中的扩展方法予以简化：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index2(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; firstName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; lastName, DateTime? birthday, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;? sex) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = repository.Query()&lt;br/&gt;        .WhereIf(e =&amp;gt; e.FirstName.Contains(firstName), firstName.IsNotNullAndEmpty())&lt;br/&gt;        .WhereIf(e =&amp;gt; e.LastName.Contains(lastName), lastName.IsNotNullAndEmpty())&lt;br/&gt;        .WhereIf(e =&amp;gt; e.Birthday.Value.Date == birthday.Value.Date, birthday.HasValue)&lt;br/&gt;        .WhereIf(e =&amp;gt; e.Sex == sex, sex.HasValue);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&amp;quot;&lt;span style="color: #8b0000"&gt;Index&lt;/span&gt;&amp;quot;, employees);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;代码相清晰了许多，我之前的几个 MVC 项目中也是这样处理的。&lt;/p&gt;&lt;p&gt;但时间一长，我逐步也发现了这种方式一些不足之处：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;首先，网站中有很多类似的查询，如Customer、Order、Product 等等。而且大致也有点规律：字符串的一般模糊查询，时间日期类的一般按日期查询（忽略时间），其它类型则相等查询。不同 Model 查询的 Action 编码总有八、九分相似，但又&lt;strong&gt;&lt;font color="#c0504d"&gt;不是简单的重复，却又难以重构&lt;/font&gt;&lt;/strong&gt;。 &lt;/li&gt;  &lt;li&gt;需求变动，如增加一个查询条件，修改 View 是必须的，但也要修改 Action，增加一个参数，还要加一行 Where 或 WhereIf。&lt;strong&gt;&lt;font color="#c0504d"&gt;简单变动却多处修改&lt;/font&gt;&lt;/strong&gt;，烦人啊，而且这种需求变动又是比较频繁的，尤其是在项目初期。若能只修改 View 而不修改 Action 就爽了。 &lt;/li&gt;  &lt;li&gt;… &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;思考后，我决定使用 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 作为查询 Action的参数来弥补这些不足。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用 Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; 作为 Action 的参数&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;试看如下代码：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index3(Expression&amp;lt;Func&amp;lt;Employee, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; predicate) {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; employees = repository.Query().Where(predicate);&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&amp;quot;&lt;span style="color: #8b0000"&gt;Index&lt;/span&gt;&amp;quot;, employees);&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;我将 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 作为 Action 的唯一的参数（暂不考虑分页、排序等），将所有的查询条件都统一汇集至&amp;#160; predicate 参数。&lt;/p&gt;&lt;p&gt;所有的查询（不管是 Employee 还是 Customer）都使用如上代码。其它实体查询只需修改参数的类型，如 Customer 查询改为 Expression&amp;lt;Func&amp;lt;Customer, bool&amp;gt;&amp;gt; 。&lt;/p&gt;&lt;p&gt;细心品味下，相信你能理解这种做法的精妙之处！&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;如上修改代码后，直接运行会报错，因为 MVC 中默认的数据绑定器 DefaultModelBinder 不能正确绑定 Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; 类型的参数。&lt;/p&gt;&lt;p&gt;我们要新创一个新的 ModelBinder。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;创建 QueryConditionExpressionModelBinder&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们需要一个新的 ModelBinder 来为 Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; 类型的参数赋值，且命名为 QueryConditionExpressionModelBinder。&lt;/p&gt;&lt;p&gt;QueryConditionExpressionModelBinder 要根据上下文来自动生成查询的 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt;。主要关注的上下文有两点：首先是当前 Model 的类型，即 typeof(T)；其次是 Request 提供的值，可通过 ValueProvider 获取。&lt;/p&gt;&lt;p&gt;下面给出一个粗略实现，仅用来说明这个思路是可行的：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;&lt;br/&gt;&lt;span&gt;18&lt;/span&gt;&lt;br/&gt;&lt;span&gt;19&lt;/span&gt;&lt;br/&gt;&lt;span&gt;20&lt;/span&gt;&lt;br/&gt;&lt;span&gt;21&lt;/span&gt;&lt;br/&gt;&lt;span&gt;22&lt;/span&gt;&lt;br/&gt;&lt;span&gt;23&lt;/span&gt;&lt;br/&gt;&lt;span&gt;24&lt;/span&gt;&lt;br/&gt;&lt;span&gt;25&lt;/span&gt;&lt;br/&gt;&lt;span&gt;26&lt;/span&gt;&lt;br/&gt;&lt;span&gt;27&lt;/span&gt;&lt;br/&gt;&lt;span&gt;28&lt;/span&gt;&lt;br/&gt;&lt;span&gt;29&lt;/span&gt;&lt;br/&gt;&lt;span&gt;30&lt;/span&gt;&lt;br/&gt;&lt;span&gt;31&lt;/span&gt;&lt;br/&gt;&lt;span&gt;32&lt;/span&gt;&lt;br/&gt;&lt;span&gt;33&lt;/span&gt;&lt;br/&gt;&lt;span&gt;34&lt;/span&gt;&lt;br/&gt;&lt;span&gt;35&lt;/span&gt;&lt;br/&gt;&lt;span&gt;36&lt;/span&gt;&lt;br/&gt;&lt;span&gt;37&lt;/span&gt;&lt;br/&gt;&lt;span&gt;38&lt;/span&gt;&lt;br/&gt;&lt;span&gt;39&lt;/span&gt;&lt;br/&gt;&lt;span&gt;40&lt;/span&gt;&lt;br/&gt;&lt;span&gt;41&lt;/span&gt;&lt;br/&gt;&lt;span&gt;42&lt;/span&gt;&lt;br/&gt;&lt;span&gt;43&lt;/span&gt;&lt;br/&gt;&lt;span&gt;44&lt;/span&gt;&lt;br/&gt;&lt;span&gt;45&lt;/span&gt;&lt;br/&gt;&lt;span&gt;46&lt;/span&gt;&lt;br/&gt;&lt;span&gt;47&lt;/span&gt;&lt;br/&gt;&lt;span&gt;48&lt;/span&gt;&lt;br/&gt;&lt;span&gt;49&lt;/span&gt;&lt;br/&gt;&lt;span&gt;50&lt;/span&gt;&lt;br/&gt;&lt;span&gt;51&lt;/span&gt;&lt;br/&gt;&lt;span&gt;52&lt;/span&gt;&lt;br/&gt;&lt;span&gt;53&lt;/span&gt;&lt;br/&gt;&lt;span&gt;54&lt;/span&gt;&lt;br/&gt;&lt;span&gt;55&lt;/span&gt;&lt;br/&gt;&lt;span&gt;56&lt;/span&gt;&lt;br/&gt;&lt;span&gt;57&lt;/span&gt;&lt;br/&gt;&lt;span&gt;58&lt;/span&gt;&lt;br/&gt;&lt;span&gt;59&lt;/span&gt;&lt;br/&gt;&lt;span&gt;60&lt;/span&gt;&lt;br/&gt;&lt;span&gt;61&lt;/span&gt;&lt;br/&gt;&lt;span&gt;62&lt;/span&gt;&lt;br/&gt;&lt;span&gt;63&lt;/span&gt;&lt;br/&gt;&lt;span&gt;64&lt;/span&gt;&lt;br/&gt;&lt;span&gt;65&lt;/span&gt;&lt;br/&gt;&lt;span&gt;66&lt;/span&gt;&lt;br/&gt;&lt;span&gt;67&lt;/span&gt;&lt;br/&gt;&lt;span&gt;68&lt;/span&gt;&lt;br/&gt;&lt;span&gt;69&lt;/span&gt;&lt;br/&gt;&lt;span&gt;70&lt;/span&gt;&lt;br/&gt;&lt;span&gt;71&lt;/span&gt;&lt;br/&gt;&lt;span&gt;72&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; QueryConditionExpressionModelBinder : IModelBinder {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; modelType = GetModelTypeFromExpressionType(bindingContext.ModelType);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (modelType == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = &lt;span style="color: #0000ff"&gt;default&lt;/span&gt;(Expression);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; parameter = Expression.Parameter(modelType, modelType.Name);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; property &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; modelType.GetProperties()){&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; queryValue = GetValueAndHandleModelState(property, bindingContext.ValueProvider, controllerContext.Controller);&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (queryValue == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            Expression proeprtyCondition = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (property.PropertyType == &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)){&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(queryValue &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)){&lt;br/&gt;                    proeprtyCondition = parameter&lt;br/&gt;                        .Property(property.Name)&lt;br/&gt;                        .Call(&amp;quot;&lt;span style="color: #8b0000"&gt;Contains&lt;/span&gt;&amp;quot;, Expression.Constant(queryValue));&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (property.PropertyType == &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (DateTime?)){&lt;br/&gt;                proeprtyCondition = parameter&lt;br/&gt;                    .Property(property.Name)&lt;br/&gt;                    .Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Value&lt;/span&gt;&amp;quot;)&lt;br/&gt;                    .Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Date&lt;/span&gt;&amp;quot;)&lt;br/&gt;                    .Equal(Expression.Constant(queryValue));&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;{&lt;br/&gt;                proeprtyCondition = parameter&lt;br/&gt;                    .Property(property.Name)&lt;br/&gt;                    .Equal(Expression.Constant(queryValue));&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (proeprtyCondition != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br/&gt;                body = body != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ? body.AndAlso(proeprtyCondition) : proeprtyCondition;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (body == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) body = Expression.Constant(&lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; body.ToLambda(parameter);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// 获取 Expression&amp;lt;Func&amp;lt;TXXX, bool&amp;gt;&amp;gt; 中 TXXX 的类型&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Type GetModelTypeFromExpressionType(Type lambdaExpressionType) {&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (lambdaExpressionType.GetGenericTypeDefinition() != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (Expression&amp;lt;&amp;gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; funcType = lambdaExpressionType.GetGenericArguments()[0];&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (funcType.GetGenericTypeDefinition() != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (Func&amp;lt;,&amp;gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; funcTypeArgs = funcType.GetGenericArguments();&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (funcTypeArgs[1] != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; funcTypeArgs[0];&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// 获取属性的查询值并处理 Controller.ModelState &lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #808080"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; GetValueAndHandleModelState(PropertyInfo property, IValueProvider valueProvider, ControllerBase controller) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; result = valueProvider.GetValue(property.Name);&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (result == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; modelState = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ModelState {Value = result};&lt;br/&gt;        controller.ViewData.ModelState.Add(property.Name, modelState);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;{&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;value&lt;/span&gt; = result.ConvertTo(property.PropertyType);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception ex){&lt;br/&gt;            modelState.Errors.Add(ex);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;了解这段代码，需要 MVC 和 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 的一些知识。这段代码还用到了 Expression 扩展方法，参见：《&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html"&gt;c# 扩展方法奇思妙用基础篇九：Expression 扩展&lt;/a&gt;》。&lt;/p&gt;&lt;p&gt;如果不想在 Global.asax 文件中设置 Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; 的 ModelBinder， 可以借助用下面这个 Attribute 类：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;font color="#008080"&gt;QueryConditionBinderAttribute&lt;/font&gt; : CustomModelBinderAttribute {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IModelBinder GetBinder() {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; QueryConditionExpressionModelBinder();&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Index3 简单修改如下：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index3(&lt;font style="background-color: #ffff00"&gt;[&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;font color="#008080"&gt;QueryConditionBinder&lt;/font&gt;]&lt;/font&gt;Expression&amp;lt;Func&amp;lt;Employee, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; predicate) { &lt;span style="color: #008000"&gt;//... &lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/span&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;下面是一个调试截图，绑定正常。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/ldp615/201109/201109162227456984.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/ldp615/201109/201109162228405336.png" width="790" height="96" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;再次说明：本部分代码仅用来说明思路可行，用了大量的硬编码。&lt;/p&gt;&lt;p&gt;我也正在准备编写一个更加灵活 QueryConditionExpressionModelBinder，来应对复杂的查询（如时间范围、值大于、小于等、以及限制对某些属性的查询），目前也有了一个大体的思路，初步完成后在之后的博文中和大家分享下。如果你有好的思路，不妨写在回复中。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;源码下载：&lt;a href="http://files.cnblogs.com/ldp615/MvcQuery.rar"&gt;MvcQuery.rar&lt;/a&gt;&amp;#160;&lt;font color="#666666"&gt;（VS2010 MVC3 项目，1758KB）&lt;/font&gt;&lt;/p&gt;&lt;p&gt;在线演示：&lt;a href="http://asp-net-mvc-expression-trees-as-action-parameter.ldp.me" target="_blank"&gt;http://asp-net-mvc-expression-trees-as-action-parameter.ldp.me&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;font color="#4f81bd"&gt;将 MVC 发挥到极致，是我的追求！&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2179276.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/16/asp-net-mvc-expression-trees-as-action-parameter.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html</id><title type="text">c# 扩展方法奇思妙用基础篇九：Expression 扩展</title><summary type="text">使用 Expression 类创建 Expression Trees 的代码往往比较繁琐，可以借助扩展方法予以简化。</summary><published>2011-09-15T09:18:00Z</published><updated>2011-09-15T09:18:00Z</updated><author><name>鹤冲天</name><uri>http://www.cnblogs.com/ldp615/</uri></author><link rel="alternate" href="http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html"/><content type="html">&lt;p&gt;.net 中创建 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx" target="_blank"&gt;Expression Trees&lt;/a&gt; 最简单的方式是使用 lambda 表达式：&lt;/p&gt;  &lt;table class="code-table"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="number"&gt;         &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        Expression&amp;lt;Func&amp;lt;Person, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; exp =&lt;br/&gt;    p =&amp;gt; p.Name.Contains(&amp;quot;&lt;span style="color: #8b0000"&gt;ldp&lt;/span&gt;&amp;quot;) &amp;amp;&amp;amp; p.Birthday.Value.Year &amp;gt; 1990;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;其中 Person 类定义如下：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Person {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DateTime? Birthday { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;但有些时候，要动态创建 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt;，我们要用到 &lt;a href="http://msdn.microsoft.com/zh-cn/library/system.linq.expressions.aspx" target="_blank"&gt;System.Linq.Expressions&lt;/a&gt; 命名空间中的 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb356138.aspx"&gt;Expression 类&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;使用 &lt;a href="http://msdn.microsoft.com/zh-cn/library/bb356138.aspx"&gt;Expression 类&lt;/a&gt; 中的静态方法，前面的 &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx"&gt;Expression Trees&lt;/a&gt; 可如下创建：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; parameter = Expression.Parameter(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Person), &amp;quot;&lt;span style="color: #8b0000"&gt;p&lt;/span&gt;&amp;quot;);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; left = Expression.Call(&lt;br/&gt;    Expression.Property(parameter, &amp;quot;&lt;span style="color: #8b0000"&gt;Name&lt;/span&gt;&amp;quot;),&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;).GetMethod(&amp;quot;&lt;span style="color: #8b0000"&gt;Contains&lt;/span&gt;&amp;quot;),&lt;br/&gt;    Expression.Constant(&amp;quot;&lt;span style="color: #8b0000"&gt;ldp&lt;/span&gt;&amp;quot;));&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; right = Expression.GreaterThan(&lt;br/&gt;    &lt;font style="background-color: #ffff00"&gt;Expression.Property(Expression.Property(Expression.Property(&lt;/font&gt;parameter, &amp;quot;&lt;span style="color: #8b0000"&gt;Birthday&lt;/span&gt;&amp;quot;), &amp;quot;&lt;span style="color: #8b0000"&gt;Value&lt;/span&gt;&amp;quot;), &amp;quot;&lt;span style="color: #8b0000"&gt;Year&lt;/span&gt;&amp;quot;),&lt;br/&gt;    Expression.Constant(1990));&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; body = Expression.AndAlso(left, right);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; lambda = Expression.Lambda&amp;lt;Func&amp;lt;Person, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;(body, parameter);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;你应该注意到第 7 行&lt;font style="background-color: #ffff00"&gt;高亮部分&lt;/font&gt;，三个重复的 Expression.Property，显得非常臃肿，导致可读性也很差。&lt;/p&gt;&lt;p&gt;可以用下面几个扩展方法予以简化：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;&lt;br/&gt;&lt;span&gt;5&lt;/span&gt;&lt;br/&gt;&lt;span&gt;6&lt;/span&gt;&lt;br/&gt;&lt;span&gt;7&lt;/span&gt;&lt;br/&gt;&lt;span&gt;8&lt;/span&gt;&lt;br/&gt;&lt;span&gt;9&lt;/span&gt;&lt;br/&gt;&lt;span&gt;10&lt;/span&gt;&lt;br/&gt;&lt;span&gt;11&lt;/span&gt;&lt;br/&gt;&lt;span&gt;12&lt;/span&gt;&lt;br/&gt;&lt;span&gt;13&lt;/span&gt;&lt;br/&gt;&lt;span&gt;14&lt;/span&gt;&lt;br/&gt;&lt;span&gt;15&lt;/span&gt;&lt;br/&gt;&lt;span&gt;16&lt;/span&gt;&lt;br/&gt;&lt;span&gt;17&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ExpressionExtensions {&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Expression AndAlso(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Expression left, Expression right) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Expression.AndAlso(left, right);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Expression Call(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Expression instance, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; methodName, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt; Expression[] arguments) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Expression Property(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Expression expression, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; propertyName) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Expression.Property(expression, propertyName);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Expression GreaterThan(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Expression left, Expression right) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Expression.GreaterThan(left, right);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Expression&amp;lt;TDelegate&amp;gt; ToLambda&amp;lt;TDelegate&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Expression body, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt;  ParameterExpression[] parameters) {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Expression.Lambda&amp;lt;TDelegate&amp;gt;(body, parameters);&lt;br/&gt;    }&lt;br/&gt;}      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这五个扩展方法相当简单，没什么技术含量。可以根据自己需要，添加更多的扩展方法。&lt;/p&gt;&lt;p&gt;前面的代码简化成：&lt;/p&gt;&lt;table class="code-table"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td class="number"&gt;        &lt;span&gt;1&lt;/span&gt;&lt;br/&gt;&lt;span&gt;2&lt;/span&gt;&lt;br/&gt;&lt;span&gt;3&lt;/span&gt;&lt;br/&gt;&lt;span&gt;4&lt;/span&gt;      &lt;/td&gt;      &lt;td class="code"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; parameter = Expression.Parameter(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Person), &amp;quot;&lt;span style="color: #8b0000"&gt;p&lt;/span&gt;&amp;quot;);&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; left = parameter.Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Name&lt;/span&gt;&amp;quot;).Call(&amp;quot;&lt;span style="color: #8b0000"&gt;Contains&lt;/span&gt;&amp;quot;, Expression.Constant(&amp;quot;&lt;span style="color: #8b0000"&gt;ldp&lt;/span&gt;&amp;quot;));&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; right = parameter.Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Birthday&lt;/span&gt;&amp;quot;).Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Value&lt;/span&gt;&amp;quot;).Property(&amp;quot;&lt;span style="color: #8b0000"&gt;Year&lt;/span&gt;&amp;quot;).GreaterThan(Expression.Constant(1990));&lt;br/&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; lambda = left.AndAlso(right).ToLambda&amp;lt;Func&amp;lt;Person, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;(parameter);      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;是不是好多了。&lt;/p&gt;&lt;p&gt;简单编码，快乐生活！&lt;/p&gt;&lt;div style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; background-color: #fff0f0; margin: 10px; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;strong&gt;《&lt;/strong&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html"&gt;&lt;strong&gt;c#扩展方法奇思妙用&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;》系统文章从 2009 年 08 月开始写起，到现在一共有了 24 篇，欢迎阅读：&lt;/strong&gt;   &lt;table style="margin: 15px" border="0" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;基础篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/07/1541376.html"&gt;中文处理&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/14/1546437.html"&gt;string 常用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/14/1552133.html"&gt;byte 常用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/01/27/random-extensions.html"&gt;Random 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/01/28/dictionary-extensions.html"&gt;Dictionary&amp;lt;TKey, TValue&amp;gt; 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/17/WhereIf-ExtensionMethod.html"&gt;WhereIf 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/18/IsBetween-ExtensionMethod.html"&gt;IsBetween 通用扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/02/17/WhereIf-ExtensionMethod.html"&gt;WhereIf 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html"&gt;Distinct 扩展&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;高级篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/08/1541641.html"&gt;改进 Scottgu 的 &amp;quot;In&amp;quot; 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/12/1544688.html"&gt;Aggregate扩展其改进&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/17/1548369.html"&gt;Enumerable.Cast&amp;lt;T&amp;gt;应用&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/29/1555309.html"&gt;对扩展进行分组管理&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/09/02/1559020.html"&gt;ToString(string format) 扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/11/08/1598596.html"&gt;WinForm 控件选择器&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/11/09/1599312.html"&gt;树”通用遍历器&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html"&gt;Type类扩展&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;变态篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/10/1542599.html"&gt;由Fibonacci数列引出“委托扩展”及“递推递归委托”&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/13/1545312.html"&gt;封装 if/else、swith/case及while&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/18/1549159.html"&gt;switch/case 组扩展&lt;/a&gt;、&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/26/1554524.html"&gt;string 的翻身革命&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;性能篇&lt;strong&gt;：&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2009/08/15/1546895.html"&gt;扩展方法性能初测&lt;/a&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="78"&gt;&lt;strong&gt;MVC篇：&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2010/04/17/TextBoxFor.html"&gt;巧用扩展方法优先级，美化所有页面TextBoxFor文本框&lt;/a&gt; &lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/ldp615/aggbug/2177783.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
