<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_XiaoMing的点滴</title><subtitle type="text">一点一滴，都是我用心写下的成长历程</subtitle><id>http://feed.cnblogs.com/blog/u/59527/rss</id><updated>2012-05-26T10:08:59Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/59527/rss"/><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/05/26/2519275.html</id><title type="text">除了Web，神马都是浮云</title><summary type="text">Win8一天天临近，几天前消费者预览版发布，发现自己提不起什么关注的热情。我曾一度想去参加Metro应用线下讲座，报名后又注销。WPF还没推广，又推出了WinRT。Metro,WinRT，还有mac和android的，学这些都是浪费青春，web开发才是人间正道。不是这些技术不好，就像买衣服，商店里琳琅满目，或者更恰当的比喻是买房子，对多数人来说，就算买得起，这是要用几十年的东西，我们不能朝三暮四，要追求投资效益最大化，成功概念最大化。 当今世界日新月异，技术革命一波接着一波，一浪高过一浪， 这场技术大潮永不退潮，身处其中，我们要明白这样的道理： 1. 如果你有能力，可能在某一阶段站在风...</summary><published>2012-05-26T07:14:00Z</published><updated>2012-05-26T07:14:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/05/26/2519275.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/05/26/2519275.html"/><content type="html">&lt;p&gt;Win8一天天临近，几天前消费者预览版发布，发现自己提不起什么关注的热情。我曾一度想去参加Metro应用线下讲座，报名后又注销。WPF还没推广，又推出了WinRT。Metro,WinRT，还有mac和android的，学这些都是浪费青春，web开发才是人间正道。不是这些技术不好，就像买衣服，商店里琳琅满目，或者更恰当的比喻是买房子，对多数人来说，就算买得起，这是要用几十年的东西，我们不能朝三暮四，要追求投资效益最大化，成功概念最大化。&lt;/p&gt;&lt;p&gt;当今世界日新月异，技术革命一波接着一波，一浪高过一浪， 这场技术大潮永不退潮，身处其中，我们要明白这样的道理：&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;1. 如果你有能力，可能在某一阶段站在风口浪尖，引领时代。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;90年代的微软，00年代的谷歌，是其中的代表。下一个可能是fackbook。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;2. 没有谁能永远站在风口浪尖之上。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;虽然这很酷，所以这么做凶险莫测，天气预报永远不可能100%精确，。微软谷歌的成功，踩着无数的尸体。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;3. 我们不能追上所有的浪头。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;除非你有流星赶月的能力，虽然乘风逐浪也很酷。趁年轻可以尝试一些新奇，但每一次都要有付出和成本的，未来，迟早你会期望投入的回报。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;4. 每波来潮中，一定有一支主流。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;潮流的方向，是由主流决定。虽然其他支流，不断涌现，有些支流看上去气势澎湃，比主流还壮观，但几乎都将逐渐消逝，或汇入主流。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;5. 一定会一支支流，以雷霆之势发展壮大，成为主流，引起新一波革命浪潮。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;VC，又称风投，没有风险不投，就是靠猜这个吃饭。&lt;/p&gt;&lt;p&gt;世界在改变，没有永远不变的方向，不要想着一劳永逸。虽然我们绝大多数人，都只能跟随潮流，只要看准主流，我们就会应付自如，才不至疲于奔命。&lt;/p&gt;&lt;p&gt;回到与我们息息相关的软件产业中，过去数十年间，虽然新技术风起云涌，好戏不断，但是总有一个主线。80和90年代是PC时代，那时计算机早已经出现许多年，编程语言也早已发展到第三代。其中有许多还耳熟的名字Cobol, Fortran, Pascal等等，先后淡出了人们的视线。C语言原来是Unix系统的脚本语言，随着Unix推广而流行，后来成为跨平台的标准。简洁高效，移植性好，又具有所有其他结构化语言的特点，所以在众多竞争者中脱颖而出。不但至今占据编程排行榜第一宝座，而且排行榜前六，也都由一堆源于C语言&amp;ldquo;C系&amp;rdquo;语言占据。&lt;/p&gt;&lt;p&gt;回顾这段历史，我们可以看到主流技术的发展规律：本来是某个特定平台的解决方案，由于其先进特性而被人们注意，开放的特性使其可能被移植到其他平台，从而被更多人使用，又被移植到更多平台，最后形成标准，直至没有人抗拒。&lt;/p&gt;&lt;p&gt;当初如果两个大学生，都看到软件行业的前景，一个考Basic，一个考C语言，虽然后者难一些，却是有眼光的选择。&lt;/p&gt;&lt;p&gt;PC时代，软件开发领域，主流是C以及之后发展起来C++，应用于不同领域，各有所长。Visual Basic和Delphi都很酷， 但是，五年后、十年后，你的代码在哪里，你的程序谁在用？&lt;/p&gt;&lt;p&gt;90年代互联网开始萌芽，Java应运而生，2000年时，.NET作为Java的竞争者诞生。新一代，基于互联网的语言，也包括Python, Ruby, node.js将是主流，C/C++仍然不可或缺，领域或日益缩小。&lt;/p&gt;&lt;p&gt;当局者迷，旁观者清，虽然现在信息途径畅通，仍然很难预测技术的走向。但我们至少可以大致描述技术的趋势，什么技术顺应了这种趋势，什么技术是倒退（即使看上去酷）。互联网时代，要求彻底的开放性和一致性，空前地扩展性和兼容性。&lt;/p&gt;&lt;p&gt;苹果就是这方面极端的反例，Mac和IPhone系列上的技术，封闭又霸道。这种模式，再成功也只是苹果一家公司的成功，而不能惠及业界，带动整个互联网发展。这种成功，是难以持续的。&lt;/p&gt;&lt;p&gt;微软是矛盾结合体，我们看到，.NET是朝这个方向走的，尽管.NET是微软的产品，但遵循的标准是跨平台的。.NET Framework的初衷也是统一开发体验，比如ADO.NET提出的数据访问模式，这种体验会不断完善，比如在ADO.NET基础上的Entity Framework。但是在UI方面，统一得不好，先是Winform，再WPF，到现在的Metro/WinRT，而MFC依然发挥作用，变化太快，选择虽然多，但都没有形成跨平台标准(Winform 有Mono实现，WPF就没有）。&lt;/p&gt;&lt;p&gt;谷歌是主流方向的坚定执行者，Web开发才是主流，Html5才是主流。桌面上的应用迟早有一天会网络化，桌面开发和Web开发将融为一体。虽然前面路还很长，未来会遇到许多障碍和阻力，但历史潮流是阻挡不了的。&lt;/p&gt;&lt;p&gt;我们应该坚定地支持Google，选择地跟随微软，坚决地远离苹果。不是说苹果的产品不要买，是对苹果的技术敬而远之，不要做水果忍者里的一只苹果。像WinRT和Metro这些东东，周末无压力时可以玩一下，对于.NET程序员，特别是新人来说，Asp.NET，WCF，多线程，应该全力深入这些核心，有闲功夫就到多在社区活动下 ，贡献源码，发文回贴都很好，让有限的精力得到最大化的利用。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2519275.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/05/26/2519275.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/05/23/2515415.html</id><title type="text">我看Chrome超越IE的意义</title><summary type="text">近日，IT界悄然上演了一场颠覆，十五年了，IE统治浏览器的时代终于落下了帷幕。 据5月份最新数据表明，Google的Chrome浏览器的全球市场份额已经超越了Microsoft的IE浏览器。 自从Netscape衰弱后，IE一度如日中天，在本世纪初数年盘踞了九成以上的市场份额，霸主地位似乎无可撼动。 在黎明前的黑夜中，Firefox揭竿而起，打破了IE的垄断，当时看上去像是蚍蜉撼大树，但随着互联网...</summary><published>2012-05-23T14:19:00Z</published><updated>2012-05-23T14:19:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/05/23/2515415.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/05/23/2515415.html"/><content type="html">&lt;p&gt;近日，IT界悄然上演了一场颠覆，十五年了，IE统治浏览器的时代终于落下了帷幕。&lt;/p&gt; &lt;p&gt;据5月份最新数据表明，Google的Chrome浏览器的全球市场份额已经超越了Microsoft的IE浏览器。&lt;/p&gt; &lt;p&gt;自从Netscape衰弱后，IE一度如日中天，在本世纪初数年盘踞了九成以上的市场份额，霸主地位似乎无可撼动。&lt;/p&gt; &lt;p&gt;在黎明前的黑夜中，Firefox揭竿而起，打破了IE的垄断，当时看上去像是蚍蜉撼大树，但随着互联网时代潮流汹涌澎湃，固步自封的IE一点点败退。Firefox如揭竿而起的陈胜，那Chrome就是刘邦，创建全新的强大王朝。&lt;/p&gt; &lt;p&gt;自从2008年诞生以来，Chrome一直就是飞速高效的印象，如今国内，诸多浏览器也采用了Chrome核心。虽然IE9也很快，但只能用于Win7和Vista，可以认为是开系统后门的结果，而Chrome则是各平台通吃。由于Android绑定google搜索，Chrome反倒没那么热心开发Android版本，直到今年才推出，只支持Android4。&lt;/p&gt; &lt;p&gt;汉朝的创立，不仅是去除暴政，从我们汉族的名称可见一斑。而我们即将迎来的，Chrome的崛起并登顶，必将在互联网时代进程打上深深的烙印。&lt;/p&gt; &lt;p&gt;在我看来，其现行意义在于：&lt;/p&gt; &lt;p&gt;1. Google搜索的领先地位更加稳固，微软推出Bing对抗Google，以一个连年亏损的部门之力对抗人家数万人公司的核心业务，本来就是很悲壮的故事，在IE雄风不再后，Bing想要超越，将书写一部无尽烧钱的血泪史。&lt;/p&gt; &lt;p&gt;看来微软也不是对IE占有率无所谓，但已经无法推出激动人心的产品了。去年Firefox4和IE9正式版几乎同时发布，24小时下载量IE9只有FF4一半不到。到现在，我仍然十分不解， 既然微软每年拿出几十亿刀贴补在线服务部门，为什么不能开发个给力的浏览器，至少得支持WinXP吧，开发好并预装个几十种插件，提供像WinRT那样友好的扩展接口。&lt;/p&gt; &lt;p&gt;2. Google掌握了互联网时代最大的话语权，不是苹果，也不是微软，规则从来都是强者制订的，Chrome的成功，可以让Google制订一系列新的标准和规则，引导Web按自己设计的轨迹发展。Google其实一直有志于此雄，已经推出了比如取代Http协议的SPDY，取代JPEG格式的WebP，最值得注意的是欲取代Javascript的Dart语言。或许这些陌生的词汇，过不几年就将成为常问的面试问题。&lt;/p&gt; &lt;p&gt;3. 将是Google生态系统有力支撑，这个系统还在初级阶段，微软的多年经营下，打造了一个windows为核心的庞大生态系统。生态系统建立，不但稳固核心业务，而且可以开拓许多新的收入来源，比如云计算，应用商店等，Google过分依赖搜索的局面有望得到改观。&lt;/p&gt; &lt;p&gt;Google如果做成自己的生态系统，一定比微软的还要开放，更不用说苹果，理论上，开放的平台扎根更深，生命力更强，Google前景将一片大好，对于互联网来说，亦是巨大的进步。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;参考：&lt;a href="http://news.cnblogs.com/n/143314/" target="_blank"&gt;IE时代终落幕&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2515415.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/05/23/2515415.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html</id><title type="text">.NET独有的精巧泛型设计模式</title><summary type="text">在.NET发展史中，2.0是具有里程碑意义的一个版本。从这个版本，.NET青出于蓝(Java)，而胜于蓝。在.NET 2.0带来的诸多新特性中，我认为泛型是最重要，没有之一。虽然泛型出现已有多年，连Java都早已借鉴引入了泛型（虽然是语法糖），可是用泛型的编程思维方式并没有得到相应的普及。一方面是由于过去大量的Framework仍然是在非泛型时代写成的，另一方面泛型的设计模式没有得到发展，改变的时候该到了。来举一个例子说明这两点。我们如果写过网络数据抓取的代码，应该熟悉这样的代码：var request = WebRequest.Create("http://www.cnblogs.</summary><published>2012-04-23T10:43:00Z</published><updated>2012-04-23T10:43:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html"/><content type="html">&lt;p&gt;在.NET发展史中，2.0是具有里程碑意义的一个版本。从这个版本，.NET青出于蓝(Java)，而胜于蓝。在.NET 2.0带来的诸多新特性中，我认为泛型是最重要，没有之一。&lt;/p&gt;&lt;p&gt;虽然泛型出现已有多年，连Java都早已借鉴引入了泛型（虽然是语法糖），可是用泛型的编程思维方式并没有得到相应的普及。一方面是由于过去大量的Framework仍然是在非泛型时代写成的，另一方面泛型的设计模式没有得到发展，改变的时候该到了。&lt;/p&gt;&lt;p&gt;来举一个例子说明这两点。我们如果写过网络数据抓取的代码，应该熟悉这样的代码：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;request = &lt;span style="color: #2b91af;"&gt;WebRequest&lt;/span&gt;.Create(&lt;span style="color: #a31515;"&gt;"http://www.cnblogs.com/"&lt;/span&gt;) &lt;span style="color: blue;"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;HttpWebRequest&lt;/span&gt;;&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;或者这么写，也是一样：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;request = &lt;span style="color: #2b91af;"&gt;HttpWebRequest&lt;/span&gt;.Create(&lt;span style="color: #a31515;"&gt;"http://www.cnblogs.com/"&lt;/span&gt;) &lt;span style="color: blue;"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;HttpWebRequest&lt;/span&gt;;&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;大家可想过，为什么每次都要as一下？&lt;/p&gt;&lt;p&gt;类似的情况还有，比如做图像处理的弟兄会熟悉：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;bm = &lt;span style="color: #2b91af;"&gt;Image&lt;/span&gt;.FromFile(&lt;span style="color: #a31515;"&gt;"e:\\me.jpg"&lt;/span&gt;) &lt;span style="color: blue;"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;;&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;和&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;bm = &lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;.FromFile(&lt;span style="color: #a31515;"&gt;"e:\\me.jpg"&lt;/span&gt;) &lt;span style="color: blue;"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;;&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我想过，但没想明白。上面两种写法，都是调用父类的工厂方法，实际返回了一个子类的实例。显然，即使不了解OCP，凭直觉也应该想到，父类的实现中不应该被子类所决定。写WebRequest和Image的前辈可能也觉得直接返回子类实例不妥，所以阴险地把方法签名的返回类型改成了父类。&lt;/p&gt;&lt;p&gt;虽然这种行径值得严重鄙视。但.NET程序员大都是人云亦云，照葫芦画瓢的好学生，所以这个问题多年了也没有修改。&lt;/p&gt;&lt;p&gt;理想的设计应该是这样：父类的每个子类，都有独立的工厂方法，返回其自身的实例。这样做法，在泛型出现前非常笨拙，得不偿失，但有了泛型，就可以精巧地实现。&lt;/p&gt;&lt;p&gt;以模拟Image类为例，Image和BitMap实现如下:&lt;/p&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Image&lt;/span&gt;&amp;lt;T&amp;gt; &lt;span style="color: blue;"&gt;where &lt;/span&gt;T:&lt;span style="color: #2b91af;"&gt;Image&lt;/span&gt;&amp;lt;T&amp;gt;, &lt;span style="color: blue;"&gt;new&lt;/span&gt;()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public string &lt;/span&gt;Path { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public static &lt;/span&gt;T FromFile(&lt;span style="color: blue;"&gt;string &lt;/span&gt;path)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return new &lt;/span&gt;T() { Path = path };&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;:&lt;span style="color: #2b91af;"&gt;Image&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;&amp;gt;&lt;br/&gt;{&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Image自身的工厂方法，就没有存在的必要了。&lt;/p&gt;&lt;p&gt;可以简单地测试一下：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;path = &lt;span style="color: #a31515;"&gt;@"e:\me.jpg"&lt;/span&gt;;&lt;br/&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;bm = &lt;span style="color: #2b91af;"&gt;Bitmap&lt;/span&gt;.FromFile(path); ;&lt;br/&gt;&lt;br/&gt;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(bm.Path);&lt;br/&gt;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(bm.GetType().Name);&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;输出结果如下：&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff;"&gt;Path: e:\me.jpg&lt;br /&gt;Type: Bitmap&lt;/span&gt;&lt;/p&gt;&lt;p&gt;为了让大家更熟悉一下，再举一个实现数据结构中的二叉树作例子。&lt;/p&gt;&lt;p&gt;传统的树节点类，无论无论C/C++/Java都是类似这样：&lt;/p&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;TreeNode&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;TreeNode &lt;/span&gt;LeftChild { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;TreeNode &lt;/span&gt;RightChild { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;TreeNode &lt;/span&gt;Parent { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public int &lt;/span&gt;Value { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;大家知道，二叉树又分好几种，AVL树、B树、红黑树等等。实现特殊的二叉树数据结构，势必要继承TreeNode。由于树节点的类型中，有类型为基类的成员，所以在子类操作这些成员时，往往也要强制转换类型，这比Image和WebRequest的例子，只在实例创建时转换类型还麻烦。&lt;/p&gt;&lt;p&gt;这就该泛型模式一显身手的好机会了，请看其父类型的实现：&lt;/p&gt;&lt;span style="color: gray;"&gt;/// &amp;lt;typeparam name="T"&amp;gt;&lt;/span&gt;&lt;span style="color: green;"&gt;Type of the node.&lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/typeparam&amp;gt;&lt;br/&gt;/// &amp;lt;typeparam name="K"&amp;gt;&lt;/span&gt;&lt;span style="color: green;"&gt;Type of the node value.&lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/typeparam&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;TreeNode&lt;/span&gt;&amp;lt;T,K&amp;gt; &lt;span style="color: blue;"&gt;where &lt;/span&gt;T:&lt;span style="color: #2b91af;"&gt;TreeNode&lt;/span&gt;&amp;lt;T,K&amp;gt; &lt;span style="color: blue;"&gt;where &lt;/span&gt;K: &lt;span style="color: #2b91af;"&gt;IComparable&lt;/span&gt;&amp;lt;K&amp;gt;&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;T LeftChild { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;T RightChild { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;T Parent { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;K Value { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;之后，实现任何一种特殊二叉树结构，比如RBTreeNode代表红黑树节点，可以这样：&lt;/p&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;RBTreeNode &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;TreeNode&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;RBTreeNode&lt;/span&gt;,&lt;span style="color: #2b91af;"&gt;Int32&lt;/span&gt;&amp;gt;&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: gray;"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green;"&gt;树节点颜色，是否为红。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray;"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;public bool &lt;/span&gt;IsRed { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public override string &lt;/span&gt;ToString()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return this&lt;/span&gt;.Value + &lt;span style="color: #a31515;"&gt;"," &lt;/span&gt;+ (&lt;span style="color: blue;"&gt;this&lt;/span&gt;.IsRed ? &lt;span style="color: #a31515;"&gt;"R" &lt;/span&gt;: &lt;span style="color: #a31515;"&gt;"B"&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这个是AVL树：&lt;/p&gt;&lt;span style="color: blue;"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;AvlTreeNode &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;TreeNode&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;AvlTreeNode&lt;/span&gt;,&lt;span style="color: #2b91af;"&gt;Int32&lt;/span&gt;&amp;gt;&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: gray;"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green;"&gt;节点的平衡度&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray;"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;public int &lt;/span&gt;Balance { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public override string &lt;/span&gt;ToString()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"Balance: " &lt;/span&gt;+ Balance + &lt;span style="color: #a31515;"&gt;", Value: " &lt;/span&gt;+ &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Value;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;不但完全符合OCP原则，而且再也不需要as来强制转换节点类型了。&lt;/p&gt;&lt;p&gt;这肯定不是我的首创，其实.NET Framework中已经不少这样的设计，比如IComparable&amp;lt;T&amp;gt;接口。也有不少优秀的框架采用了类似的设计，比如大石头同学的ORM框架NewLife.XCode。&lt;/p&gt;&lt;p&gt;看上去也很简单吧，但是很多人思维还停留在面向对象语言刚诞生的阶段，还不习惯用这种设计模式。我认为这种写法足够典型和通用，足以得上一种设计模式，而且是.NET特殊优势，独特魅力。&lt;/p&gt;&lt;p&gt;说到设计模式，其实GOF提出的23种设计模式多年了，已经过时，出现了许多新模式（比如并发编程方面，参考&lt;a href="http://en.wikipedia.org/wiki/Software_design_pattern" target="_blank"&gt;Wiki Design Pattern&lt;/a&gt;）。旧有的模式中，有的已经包含在.NET语言特性中，有的模式实现方式已经改头换面。尤其在泛型出现后，许多模式的实现可以变得简洁许多，优雅许多。&lt;/p&gt;&lt;p&gt;不要一遍遍炒过去的冷饭，设计模式应该与时俱进，永远是充满新鲜活力的话题。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2466938.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/03/03/2378478.html</id><title type="text">在WPF的Canvas上绘制二叉树</title><summary type="text">二叉树是数据结构最重要的部分之一，数据结构据说是学习编程的基础课程，虽然好像和平时工作关系不大，但面试时面试官很喜欢出点数据结构算法来刁难你。一直以来，写算法好像只是C/C++的事，一串串数字输出在冰冷的手术台，sorry，是控制台上。但中间的过程，只能画在草纸上，或者像下盲棋一样用用脑汁算。其实我们多数人并不需要到高手的那个境界，只要会走法，能走两步就够了，所以有一个棋盘的话会对我们练习帮助很大。下面是我在WPF窗口上画的一个二叉树：每个节点都是一个Canvas，里面又包含一个Ellipse和TextBlock。节点通过Margin属性来定位。在递归显示时，先计算子节点的Margin，然后再</summary><published>2012-03-03T08:59:00Z</published><updated>2012-03-03T08:59:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/03/03/2378478.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/03/03/2378478.html"/><content type="html">&lt;p&gt;二叉树是数据结构最重要的部分之一，数据结构据说是学习编程的基础课程，虽然好像和平时工作关系不大，但面试时面试官很喜欢出点数据结构算法来刁难你。&lt;/p&gt;&lt;p&gt;一直以来，写算法好像只是C/C++的事，一串串数字输出在冰冷的手术台，sorry，是控制台上。但中间的过程，只能画在草纸上，或者像下盲棋一样用用脑汁算。其实我们多数人并不需要到高手的那个境界，只要会走法，能走两步就够了，所以有一个棋盘的话会对我们练习帮助很大。&lt;/p&gt;&lt;p&gt;下面是我在WPF窗口上画的一个二叉树：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201203/201203031659146525.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201203/201203031659165280.png" alt="image" width="443" height="253" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;每个节点都是一个Canvas，里面又包含一个Ellipse和TextBlock。&lt;/p&gt;&lt;p&gt;节点通过Margin属性来定位。在递归显示时，先计算子节点的Margin，然后再通过父节点和子节点的Margin算出连线的起点和终点坐标。需要注意的是，从上到下，树枝叉的角度要依次递减，不然可能会出现节点重叠或树枝相交。&lt;/p&gt;&lt;p&gt;虽然刚开始接触WPF，不过看起来不算太难，呵呵。&lt;/p&gt;&lt;p&gt;下载地址请&lt;a href="http://files.cnblogs.com/XmNotes/binaryTreeUI.zip"&gt;点击&lt;/a&gt;。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2378478.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/03/03/2378478.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/03/01/2375109.html</id><title type="text">ADO.NET操作Oracle数据库与SQL Server的一些不同</title><summary type="text">最近用Oracle比较多，一换数据库环境才会感觉到ADO.NET是个好东西，以前用SQL Server的方式几乎能完全套用，但也有些不太一致的地方，记录一下：1. ADO.NET的Assembly，.NET Framework中的已经不被推荐使用，所以一般安装Oracle官方的Client（要求注册），会将Oracle.DataAccess.dll安装到GAC中，然后引用它。2. 在代码中，除SQL语句有一些差异外，主要注意如果要一次执行多条SQL语句，前面要加Begin，最后加End和分号，每条SQL语句间要加分号，麻烦一点。3. 数据库函数不能直接返回结果集，要通过游标参数，也稍麻烦一点。</summary><published>2012-03-01T02:22:00Z</published><updated>2012-03-01T02:22:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/03/01/2375109.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/03/01/2375109.html"/><content type="html">&lt;p&gt;最近用Oracle比较多，一换数据库环境才会感觉到ADO.NET是个好东西，以前用SQL Server的方式几乎能完全套用，但也有些不太一致的地方，记录一下：&lt;/p&gt;&lt;p&gt;1. ADO.NET的Assembly，.NET Framework中的已经不被推荐使用，所以一般安装Oracle官方的Client（要求注册），会将Oracle.DataAccess.dll安装到GAC中，然后引用它。&lt;/p&gt;&lt;p&gt;2. 在代码中，除SQL语句有一些差异外，主要注意如果要一次执行多条SQL语句，前面要加Begin，最后加End和分号，每条SQL语句间要加分号，麻烦一点。&lt;/p&gt;&lt;p&gt;3. 数据库函数不能直接返回结果集，要通过游标参数，也稍麻烦一点。&lt;/p&gt;&lt;p&gt;4. SQL Server2008起开始支持table类型存储过程参数，但对于Oracle没找到合适的办法。前不久遇到个这样的问题，最后是通过传递表对应的XML参数解决的。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Oracle还有点让人不爽，就是所有表、视图名称一律显示成大写，大家只能用下划线来组织名称的不同部分，每次要打那样的名称就难受，好在当初没有学C++和php。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2375109.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/03/01/2375109.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/02/29/2374821.html</id><title type="text">SharpDevelop使用体验</title><summary type="text">偶的笔记本硬盘前不久不争气地挂掉了，换了硬盘后，觉得VS太大了，我那年迈体弱的小本恐怕有点吃力，于是改用个第三方的IDE吧。 目前偶知道就两种，MonoDevelop和SharpDevelop。SharpDevelop历史比较久，最新版本是4.2，应该比较成熟了吧。 用了一个多月，总体感觉四个字:差强人意。下面说说它的优缺点。 优点:体积小，安装快，卸载也快 :) 缺点就多了: 1.界面风格不符合现代审美观，像win95 2.自动提示不能显示注释，又不支持查看元数据。 3.自动感知太弱，不能识别未加命名空间的类型，不能自动重命名等。 4.不能在编辑时纠正错误。 5.WPF设计器很不好用，还不时</summary><published>2012-02-29T15:29:00Z</published><updated>2012-02-29T15:29:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/02/29/2374821.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/02/29/2374821.html"/><content type="html">&lt;p&gt;偶的笔记本硬盘前不久不争气地挂掉了，换了硬盘后，觉得VS太大了，我那年迈体弱的小本恐怕有点吃力，于是改用个第三方的IDE吧。 &lt;br /&gt;目前偶知道就两种，MonoDevelop和SharpDevelop。SharpDevelop历史比较久，最新版本是4.2，应该比较成熟了吧。 &lt;br /&gt;用了一个多月，总体感觉四个字:差强人意。下面说说它的优缺点。 &lt;br /&gt;优点:体积小，安装快，卸载也快 :) &lt;br /&gt;缺点就多了: &lt;br /&gt;1.&amp;nbsp;界面风格不符合现代审美观，像win95 &lt;br /&gt;2.&amp;nbsp;自动提示不能显示注释，又不支持查看元数据。 &lt;br /&gt;3.&amp;nbsp;自动感知太弱，不能识别未加命名空间的类型，不能自动重命名等。 &lt;br /&gt;4.&amp;nbsp;不能在编辑时纠正错误。 &lt;br /&gt;5.&amp;nbsp;WPF设计器很不好用，还不时弹出错误。 &lt;br /&gt; &lt;br /&gt;这只是个人几天用下来的感觉，可能有更多的优缺点没发现。总体来说，SharpDevelop还是很不错的IDE，对于初学者还是VS适合，有些经验的在个人开发上用它不错，而且它是开源的，可以DIY，应该会很有成就感。&lt;/p&gt;&lt;p&gt;众所周知。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2374821.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/02/29/2374821.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/02/12/2348382.html</id><title type="text">看似简单类型设计题</title><summary type="text">周二去一次面试，在做一个题目中，要求实现一个学生类Student，再实现两个类继承它们，分别表示男生和女生。 当时，匆匆忙忙地，也没多想，把Student类的属性敲上，再在Boy和Girl类中的构造函数中，分别设置this.Sex = true和this.Sex = false。 实际运用中，这样肯定不合理，男生和女生的Sex是固定的（一般情况下，哈），不能在实例创建后修改。只能将Sex属性的...</summary><published>2012-02-12T13:58:00Z</published><updated>2012-02-12T13:58:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/02/12/2348382.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/02/12/2348382.html"/><content type="html">&lt;p&gt;周二去一次面试，在做一个题目中，要求实现一个学生类Student，再实现两个类继承它们，分别表示男生和女生。&lt;/p&gt;  &lt;p&gt;当时，匆匆忙忙地，也没多想，把Student类的属性敲上，再在Boy和Girl类中的构造函数中，分别设置this.Sex = true和this.Sex = false。&lt;/p&gt;  &lt;p&gt;实际运用中，这样肯定不合理，男生和女生的Sex是固定的（一般情况下，哈），不能在实例创建后修改。只能将Sex属性的set的访问级改成protected。&lt;/p&gt;  &lt;p&gt;可是，这个protected实在是太刺眼了，而且因为子类的逻辑而迫使父类作修改，既破坏了&lt;a href="http://en.wikipedia.org/wiki/Open/closed_principle" target="_blank"&gt;开放闭合(OCP)&lt;/a&gt;原则，又因为出现Student的地方不能简单地用Boy或Girl替换，违反了&lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle" target="_blank"&gt;LSP原则&lt;/a&gt;。不管我们怎么调整子类，这怎么都无法避免。&lt;/p&gt;  &lt;p&gt;解决办法还得从Student类开始，这个类应该被设计成抽象类，Sex是抽象属性，从而Boy和Girl类必须实现Sex。虽然题目中说学生要有姓名、出生日期、性别属性，但并没有说一定是具体实现，而应该结合题意通盘考虑。所以，这道题实际上我不及格。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2348382.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/02/12/2348382.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2012/01/09/2317255.html</id><title type="text">StructureMap极速上手指南（翻译）</title><summary type="text">前言：也看过一些国内介绍SM的文章，但还是老外这篇更详尽通俗。这是偶翻译的第一篇文章，错误不当之处请不吝赐教。总觉得一个第三方框架，要想成功一定要有个 响亮的名字。四年前刚接触JQuery时，就认为它一定能流行起来，因为名字叫起来明显比其它框架(Prototype/Moo Tool/Ext JS)印象深刻。StructureMap也是如此，妙得是缩写SM。IoC以前，我们常被纷繁的业务逻辑SM得痛不欲生，用StructureMap， 底层的码农看到了翻身的希望，可以SM这些业务逻辑了。我在30岁生日之际，对斯德哥尔摩EPiServer(1)组织(2)，作过一场关于IOC容器-Structure</summary><published>2012-01-09T08:17:00Z</published><updated>2012-01-09T08:17:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2012/01/09/2317255.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2012/01/09/2317255.html"/><content type="html">&lt;p&gt;&lt;em&gt;前言：也看过一些国内介绍SM的文章，但还是老外这篇更详尽通俗。这是偶翻译的第一篇文章，错误不当之处请不吝赐教。总觉得一个第三方框架，要想成功一定要有个 响亮的名字。四年前刚接触JQuery时，就认为它一定能流行起来，因为名字叫起来明显比其它框架(Prototype/Moo Tool/Ext JS)印象深刻。StructureMap也是如此，妙得是缩写SM。IoC以前，我们常被纷繁的业务逻辑SM得痛不欲生，用StructureMap， 底层的码农看到了翻身的希望，可以SM这些业务逻辑了。&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我在30岁生日之际，对斯德哥尔摩EPiServer&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r1"&gt;(1)&lt;/a&gt;&lt;/span&gt;组织&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r2"&gt;(2)&lt;/a&gt;&lt;/span&gt;，作过一场关于IOC容器-StructureMap（简称SM）的演讲。该演讲以及这篇文章的重心，不是深入IoC是什么以及它试图解决什么（已经被写过无数次了，你有兴趣的话可以看维基百科，Martin Fowler, Joel Abrahamsson, 还有StackOverflow上的文章）。我在这里要关注的是，StructureMap能为你做什么，你怎么着手做这些。&lt;/p&gt;&lt;p&gt;TLDR&lt;a href="#r3"&gt;&lt;span style="font-size: xx-small;"&gt;(3)&lt;/span&gt;&lt;/a&gt;: 这篇文章相当长，所以如果你更像是那种编译一下就运行的人，就直接把页面滚动到底下载示例解决方案吧。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一个简单服务类：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;假设你最近开始看SOLID&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r4"&gt;(4)&lt;/a&gt;&lt;/span&gt;原则，特别是依赖反转，它可能产生如下的一个代码结构：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201201/201201091617041260.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201201/201201091617077549.png" alt="image" width="399" height="228" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这样的话，我们的服务对验证和存储的抽象产生了一个构造函数依赖。存储的具体实现本身，依赖于一些配置和日志记录器。日志记录器的具体实现又依赖于其它一些抽象。当我们说具体实现时，比如说，存储的依赖于配置和日志记录意味着代码是这样：&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Repository &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;IRepository&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;Repository (&lt;span style="color: #2b91af;"&gt;IConfiguration &lt;/span&gt;configuration, &lt;span style="color: #2b91af;"&gt;ILogger &lt;/span&gt;logger)&lt;br/&gt;    {&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;创建一个我们服务的实例要像这样：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;service = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Service&lt;/span&gt;(&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Validator&lt;/span&gt;(),&lt;br/&gt;    &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Repository&lt;/span&gt;(&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Configuration&lt;/span&gt;(),&lt;br/&gt;           &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;(&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;AmAnotherNeccessaryButAtThisPointAnnoyingToTypeDependency&lt;/span&gt;())));&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这就是手动依赖注入，意思正如它听上去的，我们正在手动地把依赖注入的我们的服务中。如果你有兴趣了解更多使用IoC容器的利弊，而不是如何使用的话，我想&lt;a href="http://googletesting.blogspot.com/2009/01/when-to-use-dependency-injection.html" target="_blank"&gt;此篇文章&lt;/a&gt;作了一个很好的总结。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IoC容器&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;已经出现了许多IoC容器，我头脑中首先想到的是&lt;a href="http://structuremap.github.com/structuremap/index.html"&gt;StructureMap&lt;/a&gt;, &lt;a href="http://unity.codeplex.com/"&gt;Unity&lt;/a&gt;, &lt;a href="http://ninject.org/"&gt;Ninject&lt;/a&gt; 和&lt;a href="http://www.castleproject.org/container/gettingstarted/index.html"&gt;Castle Windsor&lt;/a&gt;。说实话我没有对不同容器间作透彻地比较。我就从StructureMap开始的，我还没有找到理由要换一个。我的理解是，所有这些框架的特性都相似，只是语法等不同。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;StructureMap和语法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;说到StructureMap的语法，知道两件事会不错：官方文档（链接在上面）覆盖面很广，可它基于旧一点的版本。这意味着如果你用一个较新的版本（我想2.5以上，本文中我在用2.6.1），你会发现许多方法找不到或过时了。另一件事是，这个框架大量地使用了多种Lambda表达式，所以如果你不太熟悉那些，当你刚开始用时，也许乍看上去它有些怪异。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;基本配置和自动装配&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;撇开语法，我们要做的基本的事是，给SturctureMap一些抽象，还有一些说明以使它能决定在实际中我们想用什么具体实现。因此，还是用同样用上面的服务做例子，当我们谈到IConfiguration抽象时，我们实际想用Configuration这个具体的类。&lt;/p&gt;&lt;p&gt;添加一个SturctureMap.dll的引用后，最简单地配置它的形式是像这样：&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt; x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IConfiguration&lt;/span&gt;&amp;gt;().Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Configuration&lt;/span&gt;&amp;gt;());&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;当我们想创建具体实现时，只要向容器发请求：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;config = &lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.GetInstance&amp;lt;&lt;span style="color: #2b91af;"&gt;IConfiguration&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;如果我们在配置如何由抽象创建类型的具体实现时失败了，SM（作者终于用缩写了）会抛出一个很友好的异常：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201201/201201091617091222.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201201/201201091617124828.png" alt="image" width="435" height="272" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;为了调试目的，想要详细了解容器内部发生了什么，也有很棒的方式，可以像这样调用WhatDoIHave（顾名思义）方法：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;what = &lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.WhatDoIHave();&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;很容易想到，要获取我们的服务（配置我们需要的依赖项后），我们会写这样的代码：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;service = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Service&lt;/span&gt;(&lt;br/&gt;    &lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.GetInstance&amp;lt;&lt;span style="color: #2b91af;"&gt;IValidator&lt;/span&gt;&amp;gt;(),&lt;br/&gt;    &lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.GetInstance&amp;lt;&lt;span style="color: #2b91af;"&gt;IRepository&lt;/span&gt;&amp;gt;());&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;使用（IoC）容器并不推荐这种方式。我们这里做的（指上面的代码）多少有些像我一开始展示的代码，而我们已经把我们的服务绑定到我们的容器了。这样不好，我们已经开始用依赖反转摆脱我们代码中对其它部分具体实现的依赖。我们想用自动装配的概念来让SM自己配置所有的依赖。&lt;/p&gt;&lt;p&gt;假设当我们向SM要我们的服务(类实例)时，它会发现最贪婪（其有最多的参数）的构造函数。在这个构造函数中，发现需要一个IValidator和IRespository（的参数）。它会查看配置，看到我们已经告诉它使用具体的类Validator和Repository. 当它尝试创建Repository时，看到又需要一个IConfiguration和一个ILogger，它又查看与之相关的配置，如此下去，直到所有的依赖被解析。所以，要得到一个Service实例我们只要这么做：&lt;/p&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;service = &lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.GetInstance&amp;lt;&lt;span style="color: #2b91af;"&gt;Service&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;自动装配和Web框架&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;不幸的是，对我们EPiServer开发者来说，WebForms在IoC方面没有得到很好的支持，采用MVC的话会让使用IoC容易得多。&lt;/p&gt;&lt;p&gt;原因是我们可以控制Controller的创建&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r5"&gt;(5)&lt;/a&gt;&lt;/span&gt;. 既然逻辑是在Controller中，这打下个很棒的基础，从而调用你的GetInstance方法，并调整自动装配而不必在你的代码中引用SM。即使你不能控制WebForm程序的Page创建，你也有办法克服-用Setter注入（&lt;a href="http://world.episerver.com/Blogs/Stefan-Forsberg/Dates/2010/3/Using-StructureMap-to-work-with-IDataFactoryFacade/" target="_blank"&gt;参考我的文章&lt;/a&gt;），只是不是那么优雅。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;程序集扫描和约定&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;如果看下我们的服务配置：&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IValidator&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Validator&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IAmAnotherNeccessaryButAtThisPointAnnoyingToTypeDependency&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;AmAnotherNeccessaryButAtThisPointAnnoyingToTypeDependency&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IRepository&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Repository&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IConfiguration&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Configuration&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;ILogger&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;&amp;gt;();&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;可以看到一个新兴的模式。我们有某种形式的抽象，叫做ISomething，还有一个具体实现叫做Something。这种（约定）非常流行，围绕它形成了SM的默认约定。这样的话，为了让它更容易以跳过许多枯燥打字工作，我们可以让SM扫描程序集，并添加所有遵循这种约定的的抽象/实现。&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    x.Scan(a =&amp;gt;&lt;br/&gt;    {&lt;br/&gt;        a.AssembliesFromApplicationBaseDirectory();&lt;br/&gt;        a.WithDefaultConventions();&lt;br/&gt;    });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们肯定可以控制想让哪些程序集被扫描。在上面的示例中，我们扫描所有在程序根目录（在Asp.Net程序中应该是bin目录）下的所有程序集。我们也可以针对某一个程序集，或正在调用程序集，或筛选以某个字符串开始的程序集&amp;hellip;&amp;hellip;没错，无所不能。&lt;/p&gt;&lt;p&gt;要是你有某种命名方面的编码规范，也可以创建自己的约定。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;注册DSL和引导&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;目前为止我们看到的示例中已经使用了SM注册DSL&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r6"&gt;(6)&lt;/a&gt;&lt;/span&gt;，推荐这种方式进行配置。通常通过一个引导器和继承注册类实现。&lt;/p&gt;&lt;p&gt;大约在你的程序入口点（比如在Asp.Net程序中的Application_Start），调用你的引导器，用来依次查看所有的注册并添加任何在它们中配置过的东西。&lt;/p&gt;&lt;p&gt;创建一个注册和从Registry类继承一样简单。我们已经看到上面的例子中，在类构造函数中能访问Registry的API。这（方式）有利于将相关联的依赖分组在一个注册中，并赋注册相应的命名。&lt;/p&gt;&lt;p&gt;假如我们想创建一个处理日志记录的注册：&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;LogRegistry &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;Registry&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;LogRegistry()&lt;br/&gt;    {&lt;br/&gt;        For&amp;lt;&lt;span style="color: #2b91af;"&gt;ILogger&lt;/span&gt;&amp;gt;()&lt;br/&gt;            .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;        For&amp;lt;&lt;span style="color: #2b91af;"&gt;IAmAnotherNeccessaryButAtThisPointAnnoyingToTypeDependency&lt;/span&gt;&amp;gt;().Use&lt;br/&gt;            &amp;lt;&lt;span style="color: #2b91af;"&gt;AmAnotherNeccessaryButAtThisPointAnnoyingToTypeDependency&lt;/span&gt;&amp;gt;();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们的引导器就像这样：&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;StructureMapBootrstrapper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public static void &lt;/span&gt;Bootstrap(&lt;span style="color: #2b91af;"&gt;IContainer &lt;/span&gt;container)&lt;br/&gt;    {&lt;br/&gt;        container.Configure(x =&amp;gt;&lt;br/&gt;        {&lt;br/&gt;            x.Scan(a =&amp;gt;&lt;br/&gt;                        {&lt;br/&gt;                            a.AssembliesFromApplicationBaseDirectory();&lt;br/&gt;                            a.LookForRegistries();&lt;br/&gt;                        });&lt;br/&gt;        });&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;要注意我们传递了一个IContainer实例（到Bootstrap方法）。我们本可以直接使用ObjectFactory（展示主要容器的一个简单静态门面），但我们想令对具体类的依赖最少。&lt;/p&gt;&lt;p&gt;在程序的入口点，只要调用我们的引导器并传递给它我们用的容器。&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;StructureMapBootrstrapper&lt;/span&gt;.Bootstrap(&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Container);&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;在这个例子中，既然那些注册（和我们之前见到其他的一样）本可以通过默认约定进行注册，我们可能还不需要一个LogRegistry。通常你会尽可能地使用默认约定，而对于不符约定的情况进行手动注册（使用注册类）。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实现转换&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;对我来说，关于IoC容器最棒的一件事是，很容易改变你的程序行为而不用直接修改代码。那只是一个配置的问题。让我们看下面的例子：我们的程序用下面的设置通过SMTP发送邮件。&lt;/p&gt;&lt;span style="color: blue;"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;void &lt;/span&gt;SendMessage(&lt;span style="color: #2b91af;"&gt;MailMessage &lt;/span&gt;message);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SendMailMessageViaSmtp &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public void &lt;/span&gt;SendMessage(&lt;span style="color: #2b91af;"&gt;MailMessage &lt;/span&gt;message)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;using &lt;/span&gt;(&lt;span style="color: blue;"&gt;var &lt;/span&gt;client = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SmtpClient&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"mail.somecompany.com"&lt;/span&gt;))&lt;br/&gt;        {&lt;br/&gt;            client.Send(message);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;MailRegistry &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;Registry&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;MailRegistry()&lt;br/&gt;    {&lt;br/&gt;        For&amp;lt;&lt;span style="color: #2b91af;"&gt;IMailService&lt;/span&gt;&amp;gt;().Use&amp;lt;&lt;span style="color: #2b91af;"&gt;MailService&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;        For&amp;lt;&lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;/span&gt;&amp;gt;().Use&amp;lt;&lt;span style="color: #2b91af;"&gt;SendMailMessageViaSmtp&lt;/span&gt;&amp;gt;();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;当我们在本机开发时，可能没有对服务器的访问权，或因某个其他原因不想发邮件。我们当然可以用多种技巧（hacks），比如在SendMailMessageViaSmtp类中注释/取消注释代码，但这最后很少能产生一个坚实的解决方案。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用剖面&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;有几种更好的方式，其中一个是使用SM中剖面（Profile）。这样可以做到为不同的剖面创建不同的配置。对于我们的开发机器，我们已经创建另一个实现&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r7"&gt;(7)&lt;/a&gt;，&lt;/span&gt;它会将邮件记录到一个文本文件中。&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;LogMailMessage &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public void &lt;/span&gt;SendMessage(&lt;span style="color: #2b91af;"&gt;MailMessage &lt;/span&gt;message)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;using&lt;/span&gt;(&lt;span style="color: blue;"&gt;var &lt;/span&gt;writer = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;StreamWriter&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"MailLog.txt"&lt;/span&gt;, &lt;span style="color: blue;"&gt;true&lt;/span&gt;))&lt;br/&gt;        {&lt;br/&gt;            writer.WriteLine(&lt;br/&gt;                &lt;span style="color: #a31515;"&gt;"Sending mailmessage from {0} to {1} with subject {2}"&lt;/span&gt;,&lt;br/&gt;                message.From.Address,&lt;br/&gt;                message.To,&lt;br/&gt;                message.Subject&lt;br/&gt;                );&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;在我们的MailRegistry中，我们创建一个叫作DEBUG的剖面，指引SM在这个剖面下使用上面这个类：&lt;/p&gt;For&amp;lt;&lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;/span&gt;&amp;gt;().Use&amp;lt;&lt;span style="color: #2b91af;"&gt;SendMailMessageViaSmtp&lt;/span&gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;Profile(&lt;span style="color: #a31515;"&gt;"DEBUG"&lt;/span&gt;, profile =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    profile.For&amp;lt;&lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;/span&gt;&amp;gt;().Use&amp;lt;&lt;span style="color: #2b91af;"&gt;LogMailMessage&lt;/span&gt;&amp;gt;();&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;接着再任意用一种我们已知的逻辑，在合适时切换剖面：&lt;/p&gt;&lt;span style="color: blue;"&gt;#if &lt;/span&gt;DEBUG&lt;br/&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Profile = &lt;span style="color: #a31515;"&gt;"DEBUG"&lt;/span&gt;;&lt;br/&gt;&lt;span style="color: blue;"&gt;#endif&lt;br/&gt;&lt;/span&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用条件逻辑&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;另一种做到切换实现的方式是在配置中使用条件。因此，先不提是否要在debug模式下构建程序，假设我们想基于机器名字切换Mail实现，使用条件语句，我们可以在下面的配置中做到：&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;ISendMailMessage&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .ConditionallyUse(c =&amp;gt;&lt;br/&gt;        {&lt;br/&gt;            c.If(context =&amp;gt; &lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.MachineName.Equals(&lt;span style="color: #a31515;"&gt;"CNNOTE41"&lt;/span&gt;))&lt;br/&gt;                .ThenIt&lt;br/&gt;                .Is&lt;br/&gt;                .ConstructedBy(by =&amp;gt; &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SendMailMessageViaSmtp&lt;/span&gt;());&lt;br/&gt;&lt;br/&gt;            c.TheDefault&lt;br/&gt;                .Is&lt;br/&gt;                .ConstructedBy(by =&amp;gt; &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;LogMailMessage&lt;/span&gt;());&lt;br/&gt;        });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;原生构造函数参数&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在一些构造函数中，你可能对某些原生类型有依赖（string, int等）。其中一个经典的例子是某种存储类会带一个连接字符串作为构造函数参数。如果我们暂时忽略，在架构观点上看这可能不是个好主意，那你使用SM的话该怎么做？&lt;/p&gt;&lt;p&gt;其实还是很简单，就像回答SM的问题，说我们想用什么参数。来给出这个存储类：&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Repository &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;IRepository&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;private string &lt;/span&gt;connectionString;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;Repository(&lt;span style="color: blue;"&gt;string &lt;/span&gt;connectionString)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;this&lt;/span&gt;.connectionString = connectionString;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public string &lt;/span&gt;GetConnectionString()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return &lt;/span&gt;connectionString;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们可以把使用连接字符串的选择，通过Ctor方法注入。&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IRepository&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Repository&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Ctor&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Is(&lt;span style="color: #a31515;"&gt;"Stefans connectionstring"&lt;/span&gt;);&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;因为我们的类只有一个构造函数包含string类型参数，SM能够推算出匹配的那个。要是有两个，我们将不得不指定哪个值属于哪个参数。要这样你只须在Ctor方法中指定一个名字。下面代码产生的会和上面一样，只是显示地指定了该设置哪个构造函数参数。&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;ObjectFactory&lt;/span&gt;.Configure(x =&amp;gt;&lt;br/&gt;{&lt;br/&gt;    x.For&amp;lt;&lt;span style="color: #2b91af;"&gt;IRepository&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Use&amp;lt;&lt;span style="color: #2b91af;"&gt;Repository&lt;/span&gt;&amp;gt;()&lt;br/&gt;        .Ctor&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #a31515;"&gt;"connectionString"&lt;/span&gt;)&lt;br/&gt;        .Is(&lt;span style="color: #a31515;"&gt;"Stefans connectionstring"&lt;/span&gt;);&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;列表和添加所有类型实现&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;设想我们在构建我们框架的一个插件部分，这里第三方程序集想让我们处理它们与一个特定接口相关的代码。这个例子多少有些不自然，是一个HelloService，它获取ISayHello（实现）的列表，并简单地循环以执行其中每个的hello方法。&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SayHelloService&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;ISayHello&lt;/span&gt;&amp;gt; helloList;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;SayHelloService(&lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;ISayHello&lt;/span&gt;&amp;gt; helloList)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;this&lt;/span&gt;.helloList = helloList;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue;"&gt;public void &lt;/span&gt;SayHello()&lt;br/&gt;    {&lt;br/&gt;        helloList.ForEach(x =&amp;gt; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.Out.WriteLine(x.Hello()));&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span style="color: blue;"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ISayHello&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;string &lt;/span&gt;Hello();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们可以指引SM扫描程序集，通过某种逻辑，来添加它找到的实现某个接口的全部类型。&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SayHelloRegistry &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;Registry&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;SayHelloRegistry()&lt;br/&gt;    {&lt;br/&gt;        Scan(a =&amp;gt;&lt;br/&gt;        {&lt;br/&gt;            a.AssembliesFromApplicationBaseDirectory();&lt;br/&gt;            a.AddAllTypesOf&amp;lt;&lt;span style="color: #2b91af;"&gt;ISayHello&lt;/span&gt;&amp;gt;();&lt;br/&gt;        });&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;因此要是我们有两个ISayHello的具体实现&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r8"&gt;(8)&lt;/a&gt;&lt;/span&gt;：&lt;/p&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SayHelloInEnglish &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;ISayHello&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public string &lt;/span&gt;Hello()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"Hello"&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color: blue;"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;SayHelloInChinese &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;ISayHello&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public string &lt;/span&gt;Hello()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"你好"&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;SM聪明到可以推算出，既然我们对ISayHello列表&lt;span style="font-size: xx-small;"&gt;&lt;a href="#r9"&gt;(9)&lt;/a&gt;&lt;/span&gt;有依赖，那就传递所有它能在配置找到的实现。所以，只要第三方想用你的插件系统来实现一个协商好的接口，你扫描他们的程序集，（这些实现）就会被自动发送给你。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;就这多了吧？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;SM肯定有比我写的更多的内容，不过这些部分是我目前在自己项目中最常用的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;示例解决方案&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我做了一个VS2010的解决方案，包含上面列出的多种SM特性的例子。你可以在&lt;a href="http://www.cloudnine.se/upload/EPiMeetupStructureMap.zip" target="_blank"&gt;这里下载&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;作者：&lt;a href="http://world.episerver.com/Blogs/Stefan-Forsberg/"&gt;Stefan Forsberg &lt;/a&gt;&lt;/p&gt;&lt;p&gt;原文：&lt;a title="http://world.episerver.com/Blogs/Stefan-Forsberg/Dates/2010/8/An-introduction-to-StructureMap/" href="http://world.episerver.com/Blogs/Stefan-Forsberg/Dates/2010/8/An-introduction-to-StructureMap/"&gt;http://world.episerver.com/Blogs/Stefan-Forsberg/Dates/2010/8/An-introduction-to-StructureMap/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;备注：&lt;/p&gt;&lt;p&gt;&lt;a name="r1"&gt;&lt;/a&gt;1) EPiServer: 是一个公司，提供强壮、灵活和可高度定制的解决方案，支持和管理公司在四个重要领域的在线展示&amp;ndash;内容管理、社区和社会媒体、商业和通信（&lt;a href="http://www.episerver.com/" target="_blank"&gt;官方网站&lt;/a&gt;）。&lt;/p&gt;&lt;p&gt;&lt;a name="r2"&gt;&lt;/a&gt;2) 这里翻译成组织，原词是Meetup，指帮助全球各地进行线下小组会议的一个在线社交网络入口（&lt;a href="http://en.wikipedia.org/wiki/Meetup" target="_blank"&gt;参考&lt;/a&gt;）。&lt;/p&gt;&lt;p&gt;&lt;a name="r3"&gt;&lt;/a&gt;3) Too long, didn&amp;rsquo;t read的缩写（太长没有看）。&lt;/p&gt;&lt;p&gt;&lt;a name="r4"&gt;&lt;/a&gt;4) 面向对象设计五原则的缩写，参考&lt;a title="http://en.wikipedia.org/wiki/SOLID" href="http://en.wikipedia.org/wiki/SOLID"&gt;http://en.wikipedia.org/wiki/SOLID&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;a name="r5"&gt;&lt;/a&gt;5) &lt;a title="which is the creamy stuff in the Oreo cookie that is MVC" href="http://vst.ensm-douai.fr/noury/20" target="_blank"&gt;原文参考链接&lt;/a&gt;。园子里也有几篇：麒麟的&lt;a href="http://www.cnblogs.com/zhuqil/archive/2010/07/27/you-have-to-knowextensibility-points-in-asp-net-mvc-controller-factory.html"&gt;Asp.net MVC2中你必须知道的扩展点（一）：Controller Factory&lt;/a&gt;，杜总的&lt;a href="http://www.cnblogs.com/dudu/archive/2011/08/15/mvc_ioc_dependency_injection.html"&gt;当ASP.NET MVC爱上IoC&lt;/a&gt;，老赵的&lt;a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/08/20/controller-factory-with-area-supporting.html" target="_blank"&gt;支持Area的ControllerFactory&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;a name="r6"&gt;&lt;/a&gt;6) DSL是Domain Specific Language的缩写。&lt;/p&gt;&lt;p&gt;&lt;a name="r7"&gt;&lt;/a&gt;7) 同样继承ISendMailMessage。好像接口名字里的Message有些累赘，叫ISendMail就好。&lt;/p&gt;&lt;p&gt;&lt;a name="r8"&gt;&lt;/a&gt;8) 原文的第二个实现是SayHelloInSwedish（瑞典语）。&lt;/p&gt;&lt;p&gt;&lt;a name="r9"&gt;&lt;/a&gt;9) 这里用集合代替更合适。因为IEnumerable&amp;lt;T&amp;gt;参数要比List&amp;lt;T&amp;gt;更具普遍性。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2317255.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2012/01/09/2317255.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2011/12/30/2307809.html</id><title type="text">两个JS控件-List和Pager</title><summary type="text">最近几个月一直在做些打杂维护的工作，博客更新得也不勤。转眼2011年将要过去了，希望来年能找回自己的激情。这两天做了两个JS控件，一个用于选择多项的List，一个显示分页页码链接等信息。一年多来一直在用JQuery，重新拾一下快忘了的基础JavaScript，顺便用在维护的项目上。在写一个查询数据页面时，由于列很多，所以又创建了一设置页面，来选择显示的列。开始时是用一个个选择框实现，像这样：所有的Checkbox的Name属性都一样，Value就是列的名称。在检测页面回发时，就可以通过Request[Name]获取到选中的值。这种方式优点是实现简单，生成的HTML代码：&lt;span&gt;</summary><published>2011-12-30T09:51:00Z</published><updated>2011-12-30T09:51:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2011/12/30/2307809.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2011/12/30/2307809.html"/><content type="html">&lt;p&gt;最近几个月一直在做些打杂维护的工作，博客更新得也不勤。转眼2011年将要过去了，希望来年能找回自己的激情。&lt;/p&gt;&lt;p&gt;这两天做了两个JS控件，一个用于选择多项的List，一个显示分页页码链接等信息。一年多来一直在用JQuery，重新拾一下快忘了的基础JavaScript，顺便用在维护的项目上。&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/XmNotes/201112/201112301751134452.png"&gt;&lt;img style="display: inline; border-width: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201112/201112301751153288.png" alt="image" width="188" height="177" border="0" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;所有的Checkbox的Name属性都一样，Value就是列的名称。在检测页面回发时，就可以通过Request[Name]获取到选中的值。这种方式优点是实现简单，生成的HTML代码：&lt;/p&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;input &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="checkbox" &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;="类别" &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;="Columns" &lt;/span&gt;&lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="c0" /&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;label &lt;/span&gt;&lt;span style="color: red;"&gt;for&lt;/span&gt;&lt;span style="color: blue;"&gt;="c0"&amp;gt;&lt;/span&gt;类别&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;label&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;input &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="checkbox" &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;="名称" &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;="Columns" &lt;/span&gt;&lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="c1" /&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;label &lt;/span&gt;&lt;span style="color: red;"&gt;for&lt;/span&gt;&lt;span style="color: blue;"&gt;="c1"&amp;gt;&lt;/span&gt;名称&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;label&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;input &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="checkbox" &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;="尺寸" &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;="Columns" &lt;/span&gt;&lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="c2" /&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;label &lt;/span&gt;&lt;span style="color: red;"&gt;for&lt;/span&gt;&lt;span style="color: blue;"&gt;="c2"&amp;gt;&lt;/span&gt;尺寸&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;label&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;span&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;p&gt;缺点是不能选择列的顺序，因此这种场合需要更给力的实现。于是我想到了ListBox-一个Asp.Net控件，古老的项目中还能见到它。虽然现在基本不会用了，但现在大家都用前端JavaScript实现它表现的形式和业务逻辑。我从网上找到一个实现，优化下结构和浏览器兼容性，展示一下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201112/201112301751181600.png"&gt;&lt;img style="display: inline; border-width: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201112/201112301751205178.png" alt="image" width="473" height="225" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这种方式要写一些Javascript，其实不算复杂，用不着JQuery。在前端的提交事件中，将选中的项写入到一个隐藏域中，后台就可以读取到这些值。&lt;/p&gt;&lt;p&gt;下面是分布控件的截图。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201112/201112312328104801.jpg"&gt;&lt;img style="display: inline; border: 0px;" title="未命名" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201112/201112312328105881.jpg" alt="未命名" width="398" height="44" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;当页数比较多时，只显示一定数目的页链接。点击&amp;lt;&amp;lt;或&amp;gt;&amp;gt;可以显示前面或后面的页。&lt;/p&gt;&lt;p&gt;数据展示页的分页可以分为参数方式和Ajax方式，前者需要对每个链接生成一个地址，后者需要执行一个JS函数。因此我定义了一个Pager对象，存储分页的参数。&lt;/p&gt;        var pager = {&lt;br /&gt;            Total: 555, //总记录数&lt;br /&gt;            Size: 20,       //每页记录数&lt;br /&gt;            LinkNumber: 10,     //显示链接数&lt;br /&gt;            //LinkAction: "#p={0}"   //链接形式&lt;br /&gt;            LinkAction: function (n) { document.title = n },    //执行JS函数形式&lt;br /&gt;            Current:18  //当前页&lt;br /&gt;        };&lt;p&gt;根据typeof(pager.LinkAction)==&amp;rsquo;string&amp;rsquo;，判断是否是纯链接。若不是，说明是Ajax刷新数据，页面不需要刷新，要复杂一些。&lt;/p&gt;&lt;p&gt;做了这两个控件后，前端的感觉又回来了。&lt;/p&gt;&lt;p&gt;下载地址：&lt;a href="http://files.cnblogs.com/XmNotes/Pager%26List.zip"&gt;http://files.cnblogs.com/XmNotes/Pager%26List.zip&lt;/a&gt;&lt;/p&gt;&lt;p&gt;下面两个应用没有JavaScript，是纯CSS的效果。我从网上借鉴的，用在今年的项目中，真得很不错、在这里再回顾一下，希望新一年里能有更多的同行用上它们。新的一年里，让Web更美好，工作更有成就感。&lt;/p&gt;&lt;p&gt;一个是层级菜单，前面文章提到过：&lt;/p&gt;&lt;p&gt;&lt;a title="http://www.cnblogs.com/XmNotes/archive/2011/04/14/2015980.html" href="http://www.cnblogs.com/XmNotes/archive/2011/04/14/2015980.html"&gt;http://www.cnblogs.com/XmNotes/archive/2011/04/14/2015980.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/XmNotes/201104/201104141415144310.png" alt="" width="331" height="269" /&gt;&lt;/p&gt;&lt;p&gt;另一个是将页脚固定在底部的技术，在这篇文章中有非常详细的介绍：&lt;a title="http://blog.jobbole.com/10408/" href="http://blog.jobbole.com/10408/"&gt;http://blog.jobbole.com/10408/&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;对今年前端工作一些回顾，2012年将到了，我将把前端的学习重心放在HTML5和CSS3上，希望新年里继续与大家，与博客园一起进步。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2307809.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2011/12/30/2307809.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/XmNotes/archive/2011/11/18/2254090.html</id><title type="text">视图分离技术的认识和应用</title><summary type="text">在过去Win32编程时代，我们看到的程序界面都是由静态编程语言，从一个按钮的尺寸到布局，一行行地绘制出来。比如现在我们创建一个.Net WinForm窗体，打开其对应的designer.cs文件，就会看到长篇累牍窗体绘制代码。 打从VB和Delphi出现后，尽管通过界面设计器自动生成代码成为主流，然而随之互联网时代的发展，我们需要丰富多样的软件界面，更灵活地应对需求变动。比如一个软件往往有多种界面...</summary><published>2011-11-18T06:45:00Z</published><updated>2011-11-18T06:45:00Z</updated><author><name>小城故事</name><uri>http://www.cnblogs.com/XmNotes/</uri></author><link rel="alternate" href="http://www.cnblogs.com/XmNotes/archive/2011/11/18/2254090.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/XmNotes/archive/2011/11/18/2254090.html"/><content type="html">&lt;p&gt;在过去Win32编程时代，我们看到的程序界面都是由静态编程语言，从一个按钮的尺寸到布局，一行行地绘制出来。比如现在我们创建一个.Net WinForm窗体，打开其对应的designer.cs文件，就会看到长篇累牍窗体绘制代码。&lt;/p&gt; &lt;p&gt;打从VB和Delphi出现后，尽管通过界面设计器自动生成代码成为主流，然而随之互联网时代的发展，我们需要丰富多样的软件界面，更灵活地应对需求变动。比如一个软件往往有多种界面，包括C/S和B/S，C/S中包括Windows/Linux/IPhone，B/S包括IE/Firefox/Chrome。无论是先设计业务，还是先构勒界面，最好能独立、清晰、明确的进行。更不想影响业务逻辑。将业务逻辑和用户界面分离，实现低耦合，变得势在必行。&lt;/p&gt; &lt;p&gt;对于三层架构的概念，相信就是初学者也耳熟能详了。对于数据访问层(DAL)和业务逻辑层(Business Logic Layer)之间的分离，比较容易理解，也不难实现。但对于业务逻辑层和界面层(UI)的分离，就不是那么泾渭分明，至少我在很长时间里都比较模糊。&lt;/p&gt; &lt;p&gt;这一方面由于理念认识的距离，一方面由于以前的框架没给予有力支持。&lt;/p&gt; &lt;p&gt;我主要从事的是.Net Web开发，闲暇里也做一些C/S程序练练手。在初学编程时，我更倾向C/S开发，因WinForm中用的是统一的强类型语言，而B/S或Asp.Net开发中，众所周知，还需要掌握HTML/CSS/JavaScript。但随之这些技能障碍被逐渐克服，以及Asp.Net开发经验的积累，我的认识发生颠覆性变化，感觉开发Asp.Net要比WinForm更清晰，更容易把握，至少不会为改一个字体或效果重新发布整个程序，除非你把这些植写到配置文件中。&lt;/p&gt; &lt;p&gt;可如果你运用了像Asp.Net那样的视图分离技术，相当于，一切UI皆可配置，而且还可以内容与样式分离，只修改样式时可以避免修改页面导致的自动编译，只要更新CSS即可。&lt;/p&gt; &lt;p&gt;视图分离另一个好处是直观，无须费神地分析一大段代码，只要瞄一眼视图模板的结构，一切就了然于心。无论是设计、开发或维护，都可以大大提高效率。正如下面语句，&lt;/p&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;content = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;@"Dear {0},&lt;br/&gt;&lt;br/&gt;                        Thank you for {1}.&lt;br/&gt;&lt;br/&gt;                        {2}"&lt;/span&gt;, receiver, thing, sender);&lt;br/&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;要优于：&lt;/p&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;content = &lt;span style="color: #a31515"&gt;"Dear " &lt;/span&gt;+ receiver + &lt;span style="color: #a31515"&gt;",\r\nThank you for " &lt;/span&gt;+ thing + &lt;span style="color: #a31515"&gt;".\r\n" &lt;/span&gt;+ sender;&lt;br/&gt;&lt;p&gt;在过去，应该是在2.0以前，Asp.Net只有页面，还有很多人固执地以C/S开发的思想做B/S，在页面后端类中生成控件，甚至直接输出html文本。 而随着MVC、Razor等技术的推广，页面的概念逐渐被模板取代。WPF和Silverlight技术，就是Asp.Net的视图分离思想在C/S开发上的移植。时至今日，视图分离技术取得了压倒性的主流地位。&lt;/p&gt;&lt;p&gt;还可以再兴几个视图分离技术的例子。&lt;/p&gt;&lt;p&gt;Visual Studio集成的ADO.Net Entity设计器（请参考园子的&lt;a href="http://kb.cnblogs.com/zt/ef/" target="_blank"&gt;AEF专题&lt;/a&gt;）：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/201111181444319406.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="285" alt="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/201111181444357864.png" width="256" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Visual Studio集成的工作流设计器（请参考麒麟同学的&lt;a href="http://www.cnblogs.com/zhuqil/tag/WF4.0/" target="_blank"&gt;WF专题&lt;/a&gt;）：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/201111181444384186.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="264" alt="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/201111181444431739.png" width="251" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;RDLC格式报表(请参考MSDN&lt;a href="http://msdn.microsoft.com/zh-cn/library/ms252073(v=VS.100).aspx" target="_blank"&gt;演练：创建 ReportViewer 报表&lt;/a&gt;)：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/201111181444523257.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="142" alt="image" src="http://images.cnblogs.com/cnblogs_com/XmNotes/201111/20111118144502597.png" width="244" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;这些视图都是基于扩展的XML定义。Html自然还是最常见XML扩展。随着浏览器差异的缩小，当你掌握Html/CSS后，开发B/S系统体验要更胜于C/S。&lt;/p&gt;&lt;p&gt;视图分离已不只是一门技术，而是软件设计中的重要思想，它分离了界面与业务逻辑的耦合，用途非常广泛。&lt;/p&gt;&lt;p&gt;最近开发一些系统服务，服务会定时做一些数据存取和分析工作，然后要将运行结果用邮件发送出去。邮件内容，要反映服务执行过程的细节。开始时做完是先定一个StringBuilder，每执行完一步，就写入执行结果，这样对简单的业务流程没问题。但实际上由于有些执行流程很长，分支很多，生成邮件内容的代码充斥各个角落，写起来很烦，维护时的可读性也很差。有时邮件格式要求稍为复杂一点，比如包含表格，开发负担会更重。 而如果最终呈现的邮件内容在在一些内在逻辑（比如对数据分析后，如果满足一定条件就生成一个报表），那就非常繁琐，会弄得你抓狂。&lt;/p&gt;&lt;p&gt;常言道，穷则思变，我把目光瞄向了视图分离。下面，将介绍邮件生成将如何运用视图分离的技术。&lt;/p&gt;&lt;p&gt;第一种方式很简单，也很好用，就是做一个邮件文本模板，将动态的要运行时生成的内容，用特殊符号标记。其实和String.Format方法的原理一样，不过待替换的字段最好不用{0}、{1}这样编号，而是用名称比如{地址}、{电话}等，可读性更好。在具体应用中，只要将动态内容以键值对形式添加到Dictionary中，而无须关心顺序问题。&lt;/p&gt;&lt;p&gt;这种方式用得很多，我看到普遍的问题是，大家都忽视了对替换内容与模板之间匹配的验证。Dictionary中的各个键，应该与模板中被替换的字段一致，不能多不能少，否则应该抛出异常，这可以有效提高系统可维护性。&lt;/p&gt;&lt;p&gt;MailBuilder类是用于创建内容基于模板的邮件，下面是它的属性：&lt;/p&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MailBuilder&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;The fields to be replaced.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;protected &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; fields = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;The resources embedded in the mail.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;protected &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;LinkedResource&lt;/span&gt;&amp;gt; resources = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;LinkedResource&lt;/span&gt;&amp;gt;();&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;The attachments to be sent out with the mail.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;protected &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Attachment&lt;/span&gt;&amp;gt; attachments = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Attachment&lt;/span&gt;&amp;gt;();&lt;br/&gt;    &lt;span style="color: blue"&gt;protected &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SmtpClient &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SmtpClient&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue"&gt;#region &lt;/span&gt;Properties&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;SMTP server location.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;Host { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Smtp credentials.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ICredentialsByHost &lt;/span&gt;Credentials { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Smtp port.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public int &lt;/span&gt;Port { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Content of mail template.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;Template { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue"&gt;string &lt;/span&gt;tempFile;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;File path of mail template.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;TemplateFile&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;tempFile; }&lt;br/&gt;        &lt;span style="color: blue"&gt;set&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            tempFile = &lt;span style="color: blue"&gt;value&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue"&gt;this&lt;/span&gt;.Template = &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.ReadAllText(tempFile);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Subject of mail&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;Subject { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;FROM address&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;From { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;TO addresses&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string&lt;/span&gt;[] To { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;CC addresses&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string&lt;/span&gt;[] CC { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;BCC addresses&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string&lt;/span&gt;[] Bcc { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Priority&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MailPriority &lt;/span&gt;Priority { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Indicates result message for sending email.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;Result { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Get or sets the reply to address of the mail message.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;ReplyTo { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color: green"&gt;Indicate whether need to return receipt. If needed, the ReplyTo value should be set first.&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public bool &lt;/span&gt;ReturnReceipt { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: blue"&gt;#endregion&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;…… ……&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这个类除有添加替换字符串AddField方法外，还支持添加DataTable和实体集合，将被转换为相应的Html表格内容。&lt;/p&gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Add a key-value pair&lt;br/&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="key"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;key's name&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="value"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;value&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;AddTable(&lt;span style="color: blue"&gt;string &lt;/span&gt;key, &lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;dt)&lt;br/&gt;&lt;br/&gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Add entities to render them as a html table.&lt;br/&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;typeparam name="T"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Entity type&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/typeparam&amp;gt;&lt;br/&gt;/// &amp;lt;param name="key"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="entities"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Entities to be rendered&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="columns"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The corresponding html table's columns.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="rowValues"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Function to get values of a row from an entity.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;AddEntities&amp;lt;T&amp;gt;(&lt;span style="color: blue"&gt;string &lt;/span&gt;key, &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;T&amp;gt; entities, &lt;span style="color: blue"&gt;string&lt;/span&gt;[] columns, &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;T, &lt;span style="color: blue"&gt;object&lt;/span&gt;[]&amp;gt; rowValues)&lt;br/&gt;&lt;p&gt;经过一段时间的使用，感觉还是相当顺手的，因此觉得拿出晒晒，希望大家不吝赐教。&lt;/p&gt;&lt;p&gt;纯文本邮件模板虽然简单方便，但对于实现逻辑复杂一点的邮件，就有点力不从心。比如邮件要示，未尾的提示，要根据前面的内容决定是否显示，我们总不能为一点差别用两个不同模板吧。于是，这种情况下我们面临新的课题—动态模板技术。其实这也不难，因为我们早就有合适的方案，就是老而弥坚XML + XSLT技术。 &lt;p&gt;这种方式，模板换成了XSLT文件。XSLT不只可以转换XML数据，还可以将动态内容以参数方式传入，.Net甚至支持XSLT中嵌入Javascript和C#。不过不推荐嵌入C#调用外部函数，那会破坏视图的本质，一般前两种方式足够了。我倾向于XML传值，有层次感，贴一下转换的XSLT的代码：&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Transform XSLT file to HTML.&lt;br/&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="template"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Template's content.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="dicField"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The fields to be filled in corresponding place of the template&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;TransformXsl(&lt;span style="color: blue"&gt;string &lt;/span&gt;template, &lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; dicField)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;var &lt;/span&gt;elements = &lt;span style="color: blue"&gt;from &lt;/span&gt;field &lt;span style="color: blue"&gt;in &lt;/span&gt;dicField&lt;br/&gt;                   &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(field.Key, field.Value.Contains(&lt;span style="color: #a31515"&gt;"&amp;lt;table"&lt;/span&gt;) ? (&lt;span style="color: blue"&gt;object&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;.Parse(field.Value) : (&lt;span style="color: blue"&gt;object&lt;/span&gt;)field.Value);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue"&gt;var &lt;/span&gt;xe = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(&lt;span style="color: #a31515"&gt;"Root"&lt;/span&gt;, elements);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;writer = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;StringWriter&lt;/span&gt;())&lt;br/&gt;    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;reader = &lt;span style="color: #2b91af"&gt;XmlReader&lt;/span&gt;.Create(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;StringReader&lt;/span&gt;(template)))&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;var &lt;/span&gt;xslTransform = &lt;span style="color: blue"&gt;new &lt;/span&gt;System.Xml.Xsl.&lt;span style="color: #2b91af"&gt;XslCompiledTransform&lt;/span&gt;();&lt;br/&gt;        xslTransform.Load(reader);&lt;br/&gt;        xslTransform.Transform(xe.CreateReader(), &lt;span style="color: blue"&gt;null&lt;/span&gt;, writer);&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;writer.ToString();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;介绍XSLT转换的文章很多，大家可以参考一下，随便找两篇：&lt;a href="http://www.cnblogs.com/TerryFeng/archive/2009/08/20/1550581.html"&gt;如何使用JavaScript 结合XSLT转换XML文档&lt;/a&gt;, &lt;a href="http://www.cnblogs.com/chenxizhang/archive/2008/08/17/1269804.html" target="_blank"&gt;博客园备份档案浏览的小工具&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;这种方式的主要缺点是要求有一定XSLT语言基础，临阵磨枪学了点XSLT，对付小型应用还凑合，将来要是大规模应用，还是得专业点才行。&lt;/p&gt;&lt;p&gt;我无耻地希望，门槛可以再低点……我们学的语言已经够多了。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/XmNotes/aggbug/2254090.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/XmNotes/archive/2011/11/18/2254090.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
