<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_麒麟.NET</title><subtitle type="text">我是一个老鸟，一个很老很老的菜鸟……</subtitle><id>http://feed.cnblogs.com/blog/u/11628/rss</id><updated>2012-05-11T07:28:10Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/11628/rss"/><entry><id>http://www.cnblogs.com/kirinboy/archive/2012/05/11/eclipse4.html</id><title type="text">Eclipse 4综述</title><summary type="text">Eclipse SDK 4.x基于E4孵化器项目，是新一代构建基于Eclipse的工具和富客户端桌面应用的平台。它使得开发和组装基于Eclipse平台的应用和工具要更加容易。第一个版本（4.0）发布于2010年7月28日，4.1发布于2011年6月22日，2012年将发布Eclipse 4.2。Eclipse 3.8将和4.2同时发布，同时3.x也将停止更新。</summary><published>2012-05-11T04:38:00Z</published><updated>2012-05-11T04:38:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2012/05/11/eclipse4.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2012/05/11/eclipse4.html"/><content type="html">&lt;p&gt;&lt;strong&gt;Eclipse 4简介&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse SDK 4.x基于E4孵化器项目，是新一代构建基于Eclipse的工具和富客户端桌面应用的平台。它使得开发和组装基于Eclipse平台的应用和工具要更加容易。第一个版本（4.0）发布于2010年7月28日，4.1发布于2011年6月22日，2012年将发布Eclipse 4.2。Eclipse 3.8将和4.2同时发布，同时3.x也将停止更新。&lt;/p&gt;&lt;p&gt;Eclipse 4包含：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;基于模型的用户界面和用于程序样式的基于CSS的声明机制。这使得设计和自定义应用程序界面变得更加容易，也给UI布局带来更大的灵活性，可以使UI看起来与IDE完全不同。&lt;/li&gt;&lt;li&gt;新的面向服务的编程模型，可以更容易地使用Eclipse平台提供的应用程序服务。&lt;/li&gt;&lt;li&gt;支持依赖注入。&lt;/li&gt;&lt;li&gt;提供了一个兼容层，已有的Eclipse 3.x程序也可以利用Eclipse 4应用程序平台的新功能。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;架构概述&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse 4应用程序平台与Eclipse 3.x应用程序平台非常类似。如全部JDT和PDE、大部分Platform都和Eclipse 3.x完全相同。E4AP与Eclipse 3.x平台的不同之处在于Workbench的实现（如&lt;code&gt;org.eclipse.ui.workbench.plugin&lt;/code&gt;），以及这个新实现所依赖的技术。在发布之前，这些技术（模型化的UI、依赖注入、基于服务的编程模型、基于CSS的样式）称为&amp;ldquo;e4&amp;rdquo;，而现在，我们叫它Eclipse 4应用程序平台（E4AP）。在E4AP上端，4.0 Workbench提供了一个3.x Workbench APIs的实现，称为&lt;em&gt;兼容层&lt;/em&gt;，为已有的Eclipse 3.x应用提供向后兼容。&lt;/p&gt;&lt;p&gt;&lt;img title="" src="http://wiki.eclipse.org/images/thumb/8/80/Eclipse_4_Architecture.png/640px-Eclipse_4_Architecture.png" alt="E4AP架构" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;模型化UI&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse 4应用程序的布局现在完全支持&lt;em&gt;模型&lt;/em&gt;。它与Web页的DOM类似，描述用户界面的布局和结构，尽管还包含其他对用户不可见的元素（如命令和handler）。&lt;/p&gt;&lt;p&gt;模型化UI为自定义应用程序外观提供非常灵活的方式。应用程序的结构比3.x的透视图工厂和扩展更容易理解，因为每个元素的容器模型都设计得更好。&lt;/p&gt;&lt;p&gt;模型本身使用EMF创建和维护的，并使用EMF风格的模式来创建和添加元素。对模型的改变将立即反应在运行的应用程序中。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;模型元素&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse 4中的模型是一组接口，都以&lt;code&gt;M&lt;/code&gt;作为前置，并公开了很多getter、setter方法。Eclipse 4的模型继承了上一代Eclipse应用程序平台的最佳实践。模型化的UI描述了窗体、透视图、stacks or tiles和part，也吸收了Eclipse 3.4中的命令/处理程序/绑定这个模型。&lt;/p&gt;&lt;p&gt;E4AP提供了&lt;code&gt;MApplicationElement&lt;/code&gt;、&lt;code&gt;MUILable&lt;/code&gt;等抽象元素，以及&lt;code&gt;MWindow&lt;/code&gt;、&lt;code&gt;MPerspective&lt;/code&gt;、&lt;code&gt;MPart&lt;/code&gt;、&lt;code&gt;MMenu&lt;/code&gt;等具体元素。详细内容可以参考&lt;a href="http://wiki.eclipse.org/Eclipse4/RCP/Modeled_UI/Model_Elements"&gt;这里&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;CSS样式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;E4AP的一个主要改进就是重新思考如何处理应用程序的主题和样式。它可以对控件、窗体、对话框应用样式。这一开始可能会感到很陌生。不过UI的层次结构与HTML类似。如SWT窗体或对话框包含一个根容器&lt;code&gt;Shell&lt;/code&gt;，它又包含一些&lt;code&gt;Composite&lt;/code&gt;和&lt;code&gt;Group&lt;/code&gt;元素，每个元素又可以包含&lt;code&gt;CTabFolder&lt;/code&gt;、&lt;code&gt;Text&lt;/code&gt;、&lt;code&gt;Tree&lt;/code&gt;和&lt;code&gt;Table&lt;/code&gt;等。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;CSS映射&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;使用CSS选择器可以通过&lt;em&gt;&lt;code&gt;type#id.class&lt;/code&gt;&lt;/em&gt;这样的方式来指定元素。从E4AP到SWT的映射如下：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;type&lt;/em&gt;对应Java组件类（如&lt;code&gt;Button&lt;/code&gt;、&lt;code&gt;Composite&lt;/code&gt;等）。&lt;/li&gt;&lt;li&gt;元素可以包含很多类。E4AP公开了模型化UI元素的接口类型（如&lt;code&gt;MPart&lt;/code&gt;、&lt;code&gt;MTrimmedWindow&lt;/code&gt;）及其标签（通过类的特性（attribute)）。类的特性也可以访问SWT组件的数据值。&lt;/li&gt;&lt;li&gt;&lt;em&gt;id&lt;/em&gt;对应模型化元素的elementId。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href="http://wiki.eclipse.org/E4/CSS/SWT_Mapping"&gt;这里&lt;/a&gt;有CSS属性与SWT控件方法的映射表。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;应用样式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在CSS文件中，我们使用相关SWT控件的标示符，如下面的CSS文件：&lt;/p&gt;&lt;code&gt;Label {&lt;br/&gt;    font: Verdana 8px;&lt;br/&gt;    color: black;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Composite Label {&lt;br/&gt;    color: black;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Text {&lt;br/&gt;    font: Verdana 8px;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Composite Text {&lt;br/&gt;    background-color: white;&lt;br/&gt;    color: black;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;SashForm {&lt;br/&gt;    background-color: #c1d5ef;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;.MTrimBar {&lt;br/&gt;    background-color: #e3efff #c1d5ef;&lt;br/&gt;    color: white;&lt;br/&gt;    font: Verdana 8px;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Shell {&lt;br/&gt;    background-color: #e3efff #c1d5ef 60&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;要让你的程序使用CSS文件，可以有两种方式：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;对产品指定&lt;code&gt;applicationCSS&lt;/code&gt;文件。&lt;/li&gt;&lt;li&gt;使用主题管理器&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;如果程序样式固定，就使用第一种方式。打开RCP项目的&lt;code&gt;plugin.xml&lt;/code&gt;文件，选择&lt;code&gt;extensioni&lt;/code&gt;选项卡，向&lt;code&gt;org.eclipse.core.runtime.products&lt;/code&gt;扩展点添加&lt;code&gt;applicationCSS&lt;/code&gt;属性。该属性的值是指向CSS文件的URI，格式约定为&lt;code&gt;platform:/plugin/BundleSymbolicName/path/file&lt;/code&gt;这种格式。例如：&lt;/p&gt;&lt;code&gt;platform:/plugin/com.example.e4.rcp.todo/css/default.css&lt;br/&gt;&lt;/code&gt;&lt;p&gt;&lt;img title="" src="http://www.vogella.com/articles/Eclipse4CSS/images/xcssprop.png.pagespeed.ic.m-0VZAPPg7.png" alt="设置applicationCSS" /&gt;&lt;/p&gt;&lt;p&gt;这样，我们的程序在一开始就将应用该样式。&lt;/p&gt;&lt;p&gt;第二种方法要更灵活一些。我们定义一个对于&lt;code&gt;org.eclipse.e4.ui.css.swt.theme&lt;/code&gt;扩展点（定义ID和对CSS文件的指针）的扩展。然后为产品定义&lt;em&gt;cssTheme&lt;/em&gt;属性。主题管理器允许我们在运行时选择样式，和注册新主题。&lt;/p&gt;&lt;p&gt;我们创建&lt;code&gt;org.eclipse.e4.ui.css.swt.theme&lt;/code&gt;扩展点的两个扩展，如下图&lt;/p&gt;&lt;p&gt;&lt;img title="" src="http://www.vogella.com/articles/Eclipse4CSS/images/xtheme10.gif.pagespeed.ic.51euFmAP0B.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img title="" src="http://www.vogella.com/articles/Eclipse4CSS/images/xtheme20.gif.pagespeed.ic.I7YfiCElxq.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;创建一个&lt;code&gt;css/red.css&lt;/code&gt;文件：&lt;/p&gt;&lt;code&gt;CTabItem, ToolBar, Button, CBanner, CoolBar {&lt;br/&gt;    font-size: 9;&lt;br/&gt;    background-color: red;&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;对项目添加&lt;code&gt;cssTemplate&lt;/code&gt;参数：&lt;/p&gt;&lt;p&gt;&lt;img title="" src="http://www.vogella.com/articles/Eclipse4CSS/images/xtheme30.gif.pagespeed.ic.e_csI2XYKM.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;创建下面这个handler将选择红色样式：&lt;/p&gt;&lt;code&gt;import javax.inject.Named;&lt;br/&gt;&lt;br/&gt;import org.eclipse.e4.core.di.annotations.Execute;&lt;br/&gt;import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;&lt;br/&gt;import org.eclipse.e4.ui.workbench.IWorkbench;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;public class ThemeSwitchHandler {&lt;br/&gt;    @Execute&lt;br/&gt;    public void switchTheme(IThemeEngine engine) {&lt;br/&gt;        engine.setTheme("de.vogella.e4.todo.redtheme", true);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;在应用程序中添加一个调用上面handler的菜单。运行程序，就可以通过菜单选择红色主题：&lt;/p&gt;&lt;p&gt;&lt;img title="" src="http://www.vogella.com/articles/Eclipse4CSS/images/xtheme40.gif.pagespeed.ic.bMvGDTUJDw.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此外，我们还可以指定某个控件的标签，并在CSS文件中定义这些标签。我们可以用下面的代码来设置标签：&lt;/p&gt;&lt;code&gt;Label label = new Label(parenet, SWT.NONE);&lt;br/&gt;label.setData("org.eclipse.e4.ui.css.id","MyCSSTagForLabel");&lt;br/&gt;&lt;/code&gt;&lt;p&gt;CSS文件可以这样定义该标签的样式：&lt;/p&gt;&lt;code&gt;#MyCSSTagForLabel{&lt;br/&gt;    color:#blue;&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;&lt;strong&gt;依赖注入&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse平台经过10年的发展，仍然存在以下问题：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;代码需要频繁使用全局单例访问器（如&lt;code&gt;Platform&lt;/code&gt;、&lt;code&gt;PlatformUI&lt;/code&gt;）或请求较深的依赖链（如获取&lt;code&gt;IStatusLineManager&lt;/code&gt;）。单例服务对RAP和Riena这种应用服务器来说，问题多多。&lt;/li&gt;&lt;li&gt;单例与提供程序的消费者紧密耦合，并且禁止重用。&lt;/li&gt;&lt;li&gt;不够动态。&lt;/li&gt;&lt;li&gt;&amp;hellip;&amp;hellip;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;E4AP使用依赖注入来解决这些问题。客户端代码不需要知道如何访问服务，只需要描述所需的服务，而由平台负责配置适当的服务。它提供了与&lt;a href="http://jcp.org/en/jsr/detail?id=330"&gt;JSR 330&lt;/a&gt;兼容的&lt;a href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/package-summary.html"&gt;基于注解&lt;/a&gt;的依赖注入框架，与Spring类似。注入器定义在多个插件中：&lt;code&gt;org.eclipse.e4.core.di&lt;/code&gt;、&lt;code&gt;org.eclipse.e4.core.di.extensions&lt;/code&gt;、&lt;code&gt;org.eclipse.e4.ui.di&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;在Eclipse 3.x中，视图需要通过&lt;code&gt;PlatformUI&lt;/code&gt;单例和part site的状态行管理器来访问Eclipse帮助系统：&lt;/p&gt;&lt;code&gt;class MyView extends ViewPart {&lt;br/&gt;    public void createPartControl(Composite parent) {&lt;br/&gt;        Button button = ...;&lt;br/&gt;        PlatformUI.getWorkbench().getHelpSystem().setHelp(button, "com.example.button.help.id");&lt;br/&gt;&lt;br/&gt;        getViewSite().getActionBars().getStatusLineManager().setMessage("Configuring system...");&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;而在E4AP中，part是POJO，应用程序服务是直接注入进来的：&lt;/p&gt;&lt;code&gt;class MyView {&lt;br/&gt;    @Inject&lt;br/&gt;    public void create(Composite parent, IWorkbenchHelpSystem help) {&lt;br/&gt;        Button button = ...;&lt;br/&gt;        help.setHelp(button, "com.example.button.help.id");&lt;br/&gt;&lt;br/&gt;        slm.setMessage("Configuring system...");&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;DI的好处有：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;客户端可以编写POJO和所需的服务列表。&lt;/li&gt;&lt;li&gt;更利于测试。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;而DI也有一些缺点：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;服务发现：无法使用代码自动完成功能来找到可用的服务。&lt;/li&gt;&lt;li&gt;调试加载失败的注入项时会很困难。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;与依赖注入相关的注释，详见&lt;a href="http://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection"&gt;这里&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;上下文&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;E4AP使用&lt;em&gt;上下文&lt;/em&gt;（&lt;code&gt;IEclipseContext&lt;/code&gt;接口）向应用程序提供公共服务。普通代码不需要使用或了解上下文。应该在Java类中使用&lt;code&gt;@Inject&lt;/code&gt;注解来接收必要的服务，不应该直接使用&lt;code&gt;IEclipseContext&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;Eclipse 3.x存在以下问题，可以由&lt;code&gt;IEclipseContext&lt;/code&gt;和依赖注入来解决：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;频繁使用全局单例访问器（如&lt;code&gt;Platform&lt;/code&gt;、&lt;code&gt;PlatformUI&lt;/code&gt;等等）&lt;/li&gt;&lt;li&gt;生产者与消费者之间的耦合过于紧密，同时很难重用&lt;/li&gt;&lt;li&gt;对上下文变化的动态响应不是增量的&lt;/li&gt;&lt;li&gt;&lt;code&gt;IEvaluationContext&lt;/code&gt;包含全局状态（可根据上下文的改变而变化）&lt;/li&gt;&lt;li&gt;当前解决方案不是多线程的（计算发生在UI线程）&lt;/li&gt;&lt;li&gt;尺寸变化&lt;ul&gt;&lt;li&gt;当前解决方案不会因为服务的生命周期短而减小尺寸&lt;/li&gt;&lt;li&gt;当前解决方案会因为服务多而增大尺寸&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;包含太多相似的并行树（控件树、服务位置树等）&lt;/li&gt;&lt;li&gt;不跟踪服务的消费者&lt;/li&gt;&lt;li&gt;客户端代码需要了解Eclipse代码库的内部&lt;/li&gt;&lt;li&gt;不支持由运行时的其他服务组成的服务查找&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;E4AP的上下文存储了可用的服务，并提供了OSGi服务查找。由于不太可能向Eclipse上下文请求可用的服务，并且不建议直接调用上下文中的方法，所以了解能够注入哪些内容是十分重要的。&lt;/p&gt;&lt;p&gt;以&lt;em&gt;模型&lt;/em&gt;为例，它们都是&lt;code&gt;MContext&lt;/code&gt;的实例，包含在自身的上下文中。例如，&lt;code&gt;MWindow&lt;/code&gt;和&lt;code&gt;MPart&lt;/code&gt;都是&lt;code&gt;MContext&lt;/code&gt;，所以可以这样查询模型对象的上下文：&lt;/p&gt;&lt;code&gt;// window == mwindow&lt;br/&gt;MWindow window = (MWindow) mwindow.getContext().get(MWindow.class.getName());&lt;br/&gt;// part == mpart&lt;br/&gt;MWindow part = (MPart) mpart.getContext().get(MPart.class.getName());&lt;br/&gt;&lt;/code&gt;&lt;p&gt;这些模型对象都存在于上下文中，所以可以直接将它们注入到客户端代码中：&lt;/p&gt;&lt;code&gt;public class AccountsPart {&lt;br/&gt;    @Inject&lt;br/&gt;    private MPart part;&lt;br/&gt;&lt;br/&gt;    @Inject&lt;br/&gt;    private MWindow window;&lt;br/&gt;&lt;br/&gt;    void setDirty(boolean dirty) {&lt;br/&gt;        part.setDirty(dirty);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;为了鼓励重用，你应该注入所需的最小公分母。例如，如果只关注让part变dirty，只需要：&lt;/p&gt;&lt;code&gt;public class AccountsPart {&lt;br/&gt;    @Inject&lt;br/&gt;    private MDirtyable dirtyable;&lt;br/&gt;&lt;br/&gt;    void setDirty(boolean dirty) {&lt;br/&gt;        dirtyable.setDirty(dirty);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;这样其他非&lt;code&gt;MPart&lt;/code&gt;的&lt;code&gt;MDirtyable&lt;/code&gt;实现也可以复用你的代码。这导致了一个非常有趣的现象，即一个模型接口的上层接口也会添加到上下文中。例如：&lt;/p&gt;&lt;code&gt;public class AccountsPart {&lt;br/&gt;    @Inject&lt;br/&gt;    private MDirtyable dirtyable;&lt;br/&gt;&lt;br/&gt;    @Inject&lt;br/&gt;    private MUILabel label;&lt;br/&gt;&lt;br/&gt;    @Inject&lt;br/&gt;    private MContext context;&lt;br/&gt;&lt;br/&gt;    @Inject&lt;br/&gt;    private MPart part;&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;所有的字段都是相同的&lt;code&gt;MPart&lt;/code&gt;实例。&lt;/p&gt;&lt;p&gt;关于上下文的详细内容，请参考&lt;a href="http://wiki.eclipse.org/E4/Contexts"&gt;这里&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;事件模型&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Eclipse 4使用了一个发布/订阅事件模型的&lt;em&gt;全局事件总线&lt;/em&gt;（global event bus）。《&lt;a href="http://wiki.eclipse.org/E4/Event_Processing"&gt;E4中的事件处理&lt;/a&gt;》描述了其原理。全局事件总线实现在OSGi事件引起之上，可使用&lt;code&gt;org.eclipse.e4.core.services.events.IEventBroker&lt;/code&gt;访问。&lt;/p&gt;&lt;p&gt;&lt;code&gt;IEventBroker&lt;/code&gt;提供了一些方法，可以订阅、取消订阅总线上的事件，以及向总线发布事件。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;获取IEventBroker&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;可以通过&lt;code&gt;EclipseContext&lt;/code&gt;来获取&lt;code&gt;IEventBroker&lt;/code&gt;的一个实例：&lt;/p&gt;&lt;code&gt;&amp;hellip;&lt;br/&gt;private IEclipseContext eclipseContext;&lt;br/&gt;&amp;hellip;&lt;br/&gt;IEventBroker eventBroker = eclipseContext.get(IEventBroker.class);&lt;br/&gt;&lt;/code&gt;&lt;p&gt;或通过依赖注入：&lt;/p&gt;&lt;code&gt;@Inject&lt;br/&gt;IEventBroker eventBroker;&lt;br/&gt;&lt;/code&gt;&lt;p&gt;&lt;strong&gt;发布事件&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;向全局事件总线发布事件十分简单，只需调用一下两个方法之一：&lt;/p&gt;&lt;code&gt;IEvent  Broker.post(String topic, Object data) // synchronous delivery&lt;br/&gt;&lt;br/&gt;IEventBroker.send(String topic, Object data) // asynchronous delivery&lt;br/&gt;&lt;/code&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;code&gt;...&lt;br/&gt;foo.Bar payload = getPayload();&lt;br/&gt;boolean wasDispatchedSuccessfully = eventBroker.send(TOPIC_STRING, payload);&lt;br/&gt;&lt;/code&gt;&lt;p&gt;如果&lt;code&gt;send&lt;/code&gt;或&lt;code&gt;post&lt;/code&gt;命令的&lt;code&gt;payload&lt;/code&gt;是普通Java对象，将把它作为包含&lt;code&gt;IEventBroker.DATA&lt;/code&gt;键的属性附加到OSGi事件上。如果&lt;code&gt;payload&lt;/code&gt;是&lt;code&gt;Dictionary&lt;/code&gt;或&lt;code&gt;Map&lt;/code&gt;，所有的值都将作为包含相应键的属性进行添加。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;响应事件&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;声明和相应事件包含两种方法：依赖注入和通过&lt;code&gt;IEventBroker&lt;/code&gt;订阅。&lt;/p&gt;&lt;p&gt;Eclipse推荐在任何时候都使用依赖注入来注册和相应事件。它的代码更少，更容易阅读和维护，包含较少的匿名内部类。（但实际上E4代码库并没有使用这种方法来订阅事件。）&lt;/p&gt;&lt;code&gt;@Inject @Optional&lt;br/&gt;void closeHandler(@UIEventTopic(''TOPIC_STRING'') foo.Bar payload) {&lt;br/&gt;    // Useful work that has access to payload.  The instance of foo.Bar that the event poster placed on the global event bus with the topic ''TOPIC_STRING''&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;应该将事件处理方法定义为私有的，这样可以更清晰，也能避免直接调用。依赖注入机制可以注入私有字段和方法。（目前定义成私有方法会有bug，可以定义为包级私有。）&lt;/p&gt;&lt;p&gt;如果你的类没有使用依赖注入，则只能用&lt;code&gt;IEventBroker&lt;/code&gt;来订阅：&lt;/p&gt;&lt;code&gt;IEventBroker eventBroker;&lt;br/&gt;&amp;hellip;&lt;br/&gt;void addSubscribers() {&lt;br/&gt;&lt;br/&gt;    eventBroker.subscribe(TOPIC_STRING, closeHandler);&lt;br/&gt;    &amp;hellip;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;void removeSubscribers() {&lt;br/&gt;    eventBroker.unsubscribe(closeHandler);&lt;br/&gt;    &amp;hellip;&lt;br/&gt;}&lt;br/&gt;&amp;hellip;&lt;br/&gt;private org.osgi.service.event.EventHandler closeHandler = new EventHandler() {&lt;br/&gt;    public void handleEvent(Event event) {&lt;br/&gt;&lt;br/&gt;    // Useful work that has access&lt;br/&gt;    foo.Bar payload = (foo.Bar) event.getProperty(IEventBroker.DATA);&lt;br/&gt;}&lt;br/&gt;&lt;/code&gt;&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.eclipse.org/Eclipse4/RCP"&gt;Eclipse 4 RCP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.eclipse.org/Eclipse4/Tutorials"&gt;Eclipse 4 Tutorials&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.eclipse.org/Eclipse4/FAQ"&gt;Eclipse 4 FAQ&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2495794.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2012/05/11/eclipse4.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2012/03/26/2418064.html</id><title type="text">Hibernate里自定义UserType时取不到值的问题</title><summary type="text">前两天我微博提到有个BUG出现了两个月却还没有头绪。这个BUG是这样的：在Hibernate中自定义UserType，从数据库中取值的时候，有时候这个UserType能取到值，但有时候即使数据库有值，取到的也是null。后来负责前端的同事偶然发现，当数据库中某些字段为null的时候，这个UserType就取不到值，如果把这些字段填上内容，就可以取到了。于是这个问题就莫名其妙地解决了。后来经过分析和...</summary><published>2012-03-26T08:07:00Z</published><updated>2012-03-26T08:07:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2012/03/26/2418064.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2012/03/26/2418064.html"/><content type="html">&lt;p&gt;前两天我微博提到&lt;a href="http://weibo.com/1405716845/yaVafiWaW" target="_blank"&gt;有个BUG出现了两个月却还没有头绪&lt;/a&gt;。这个BUG是这样的：在Hibernate中自定义UserType，从数据库中取值的时候，有时候这个UserType能取到值，但有时候即使数据库有值，取到的也是null。后来负责前端的同事偶然发现，当数据库中某些字段为null的时候，这个UserType就取不到值，如果把这些字段填上内容，就可以取到了。于是这个问题就&lt;a href="http://weibo.com/1405716845/ybc3Sjogn" target="_blank"&gt;莫名其妙地解决了&lt;/a&gt;。后来经过分析和测试，发现只要UserType的前一个字段为null，这个UserType就肯定取不到值。UserType的代码是这样的：&lt;/p&gt;  &lt;span style="color: #ff8040"&gt;public class &lt;/span&gt;&lt;span style="color: teal"&gt;GenderUserType &lt;/span&gt;&lt;span style="color: #ff8040"&gt;extends &lt;/span&gt;&lt;span style="color: teal"&gt;StringUserType &lt;/span&gt;&lt;span style="color: #ff8000"&gt;{&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: #ff8040"&gt;public &lt;/span&gt;&lt;span style="color: teal"&gt;Class &lt;/span&gt;&lt;span style="color: #ff0080"&gt;returnedClass&lt;/span&gt;&lt;span style="color: #ff8000"&gt;() {&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: red"&gt;return &lt;/span&gt;&lt;span style="color: teal"&gt;Gender&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #ff8040"&gt;class&lt;/span&gt;&lt;span style="color: #ff8000"&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: #ff8040"&gt;public &lt;/span&gt;&lt;span style="color: teal"&gt;Object &lt;/span&gt;&lt;span style="color: #ff0080"&gt;nullSafeGet&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;ResultSet &lt;/span&gt;&lt;span style="color: #6aca00"&gt;rs&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;String&lt;/span&gt;&lt;span style="color: #ff8000"&gt;[] &lt;/span&gt;&lt;span style="color: #6aca00"&gt;names&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;Object &lt;/span&gt;&lt;span style="color: #6aca00"&gt;owner&lt;/span&gt;&lt;span style="color: #ff8000"&gt;)&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: #ff8040"&gt;throws &lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;HibernateException&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;SQLException &lt;/span&gt;&lt;span style="color: #ff8000"&gt;{&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: #ff8040"&gt;if &lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #6aca00"&gt;rs&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #4aa5ff"&gt;wasNull&lt;/span&gt;&lt;span style="color: #ff8000"&gt;())    &lt;/span&gt;&lt;span style="color: red"&gt;return &lt;/span&gt;&lt;span style="color: #ff8040"&gt;null&lt;/span&gt;&lt;span style="color: #ff8000"&gt;;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: teal"&gt;String &lt;/span&gt;&lt;span style="color: #7eca00"&gt;gender &lt;/span&gt;&lt;span style="color: #ff8000"&gt;= &lt;/span&gt;&lt;span style="color: #6aca00"&gt;rs&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #4aa5ff"&gt;getString&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #6aca00"&gt;names&lt;/span&gt;&lt;span style="color: #ff8000"&gt;[&lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;0&lt;/span&gt;&lt;span style="color: #ff8000"&gt;]);&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: red"&gt;return &lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;Gender&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #4da5ff"&gt;valueOf&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #7eca00"&gt;gender&lt;/span&gt;&lt;span style="color: #ff8000"&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: #ff8040"&gt;public void &lt;/span&gt;&lt;span style="color: #ff0080"&gt;nullSafeSet&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;PreparedStatement &lt;/span&gt;&lt;span style="color: #6aca00"&gt;st&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;Object &lt;/span&gt;&lt;span style="color: #6aca00"&gt;value&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: #ff8040"&gt;int &lt;/span&gt;&lt;span style="color: #6aca00"&gt;index&lt;/span&gt;&lt;span style="color: #ff8000"&gt;)&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: #ff8040"&gt;throws &lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;HibernateException&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: #3f7f5f"&gt;SQLException &lt;/span&gt;&lt;span style="color: #ff8000"&gt;{&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: #ff8040"&gt;if &lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #6aca00"&gt;value &lt;/span&gt;&lt;span style="color: #ff8000"&gt;== &lt;/span&gt;&lt;span style="color: #ff8040"&gt;null&lt;/span&gt;&lt;span style="color: #ff8000"&gt;) {&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: #6aca00"&gt;st&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #4aa5ff"&gt;setNull&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #6aca00"&gt;index&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: #2100bd"&gt;SQL_TYPE&lt;/span&gt;&lt;span style="color: #ff8000"&gt;);&lt;br/&gt;        }&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: #ff8040"&gt;else &lt;/span&gt;&lt;span style="color: #ff8000"&gt;{&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: teal"&gt;String &lt;/span&gt;&lt;span style="color: #7eca00"&gt;gender &lt;/span&gt;&lt;span style="color: #ff8000"&gt;= ((&lt;/span&gt;&lt;span style="color: teal"&gt;Gender&lt;/span&gt;&lt;span style="color: #ff8000"&gt;)&lt;/span&gt;&lt;span style="color: #6aca00"&gt;value&lt;/span&gt;&lt;span style="color: #ff8000"&gt;).&lt;/span&gt;&lt;span style="color: #4aa5ff"&gt;toString&lt;/span&gt;&lt;span style="color: #ff8000"&gt;();&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: #6aca00"&gt;st&lt;/span&gt;&lt;span style="color: #ff8000"&gt;.&lt;/span&gt;&lt;span style="color: #4aa5ff"&gt;setString&lt;/span&gt;&lt;span style="color: #ff8000"&gt;(&lt;/span&gt;&lt;span style="color: #6aca00"&gt;index&lt;/span&gt;&lt;span style="color: #ff8000"&gt;, &lt;/span&gt;&lt;span style="color: #7eca00"&gt;gender&lt;/span&gt;&lt;span style="color: #ff8000"&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;/span&gt;&lt;p&gt;您能看出问题在哪了吗？对了，就是nullSafeGet里的if (rs.wasNull()) return null;这句。查看wasNull的文档不难发现，这个方法用于判断上次从rs中取出的值是否为null。因此，如果这个UserType的前一个字段为null，这条语句就会返回null。当时我不知道从哪copy了这份代码，于是产生了这样一个表现十分诡异的BUG。&lt;/p&gt;&lt;p&gt;要修复这个BUG是很简单的，只需要调换nullSafeGet里前两行代码即可。&lt;/p&gt;&lt;p&gt;如果UserType是除主键外的第一个字段，在取值的时候还会产生“sqlexception 未读取数据”的异常。&lt;/p&gt;&lt;p&gt;&lt;a href="http://topic.csdn.net/u/20110713/22/5b9384fa-91ff-4086-a83c-90c89b355e19.html"&gt;http://topic.csdn.net/u/20110713/22/5b9384fa-91ff-4086-a83c-90c89b355e19.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://ytffhvk.iteye.com/blog/169306"&gt;http://ytffhvk.iteye.com/blog/169306&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://rayleeya.iteye.com/blog/365237"&gt;http://rayleeya.iteye.com/blog/365237&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2418064.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2012/03/26/2418064.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2012/03/08/should-method-return-interface-or-concrete-class-and-programming-to-an-interface.html</id><title type="text">方法该返回接口还是具体类，以及面向接口编程</title><summary type="text">这两天突然闲得蛋疼，逛了一下CSDN，发现了这篇帖子，于是引发了一场不大不小的关于方法应该返回接口or具体类，以及面向接口编程的讨论。方法的返回类型应该更抽象还是更具体，没有确切的答案，唯一正确的答案是：It depends。要时情况而定。</summary><published>2012-03-08T06:16:00Z</published><updated>2012-03-08T06:16:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2012/03/08/should-method-return-interface-or-concrete-class-and-programming-to-an-interface.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2012/03/08/should-method-return-interface-or-concrete-class-and-programming-to-an-interface.html"/><content type="html">&lt;p&gt;这两天突然闲得蛋疼，逛了一下CSDN，发现了&lt;a href="http://topic.csdn.net/u/20120307/07/6034c3bb-e5a5-4723-832d-8343b59b2781.html" target="_blank"&gt;这篇帖子&lt;/a&gt;，于是引发了一场不大不小的关于方法应该返回接口or具体类，以及面向接口编程的讨论。&lt;/p&gt;&lt;p&gt;方法的返回类型应该更抽象还是更具体，没有确切的答案，唯一正确的答案是：It depends。要时情况而定。&lt;/p&gt;&lt;p&gt;帖子里很多牛人说，像String、List&amp;lt;T&amp;gt;这样的类型，返回具体类没有什么，特别是例子里的方法，返回IList&amp;lt;T&amp;gt;就显得很白痴。我同意String这种跟基元类型差不多的类型完全可以返回具体类，但对于List&amp;lt;T&amp;gt;和IList&amp;lt;T&amp;gt;，就完全不敢苟同了。&lt;/p&gt;&lt;p&gt;因为，在设计API时（这里主要讨论方法），你需要控制留给用户&amp;ldquo;权限&amp;rdquo;。假如你的方法只希望返回一个只读的可枚举的集合类型，那么就应该返回IEnumerable&amp;lt;T&amp;gt;，这样用户就不能进行修改、添加、排序和转换。而如果你希望给用户一个不可转换的列表，就应该返回IList&amp;lt;T&amp;gt;，这样用户就不能调用ConvertAll方法。如果你希望留给用户的操作完全和List&amp;lt;T&amp;gt;一致，这时返回具体的List&amp;lt;T&amp;gt;就是最适当的。List&amp;lt;T&amp;gt;虽然十分常用，但它与IList&amp;lt;T&amp;gt;还是有区别的，不能简单地将它跟String这种类型划等号。为了验证我的想法，我在Stack Overflow上搜到了&lt;a href="http://stackoverflow.com/questions/3564264/c-why-return-a-collection-interface-rather-than-a-concrete-type" target="_blank"&gt;这个帖子&lt;/a&gt;，偶像&lt;a href="http://msmvps.com/blogs/jon_skeet/Default.aspx" target="_blank"&gt;Jon Skeet&lt;/a&gt;的回答跟我的想法不谋而合。当然，这也应该是绝大多数同学的想法。&lt;/p&gt;&lt;p&gt;我的另一个观点是：在设计API时，让方法返回接口类型是&lt;span style="background-color: #ffffff;"&gt;&lt;strong&gt;面向接口编程&lt;/strong&gt;&lt;/span&gt;的一部分。但很多人指出我对面向接口编程的理解有误。&lt;/p&gt;&lt;p&gt;这里首先要说明一下什么是面向接口编程。据我所知，这个原则最早是在《设计模式》里提出来的，即&lt;em&gt;Program to an interface, not an implementation（针对接口编程，而不是针对实现）&lt;/em&gt;。意思是指：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;我们应该根据抽象类中定义的&lt;em&gt;接口&lt;/em&gt;来操纵对象，用户只需要知道定义这些&lt;em&gt;接口&lt;/em&gt;的抽象类，而不必关心使用的是什么具体类型。&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;在声明变量时，不将变量声明为某个特定的具体类，而是让它遵从抽象类所定义的&lt;em&gt;接口&lt;/em&gt;，即将变量声明为抽象类。&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;在实例化的时候，使用创建型模式。创建型模式可以确保系统是针对&lt;em&gt;接口&lt;/em&gt;的方式书写，而不是针对实现的方式书写。&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;可以看到，这里的&lt;em&gt;接口&lt;/em&gt;，与IList&amp;lt;T&amp;gt;这种接口不是一个概念，所以我用斜体字来表示Program to an interface里的&lt;em&gt;接口&lt;/em&gt;。&lt;/p&gt;&lt;p&gt;这里的&lt;em&gt;接口&lt;/em&gt;是指，抽象类对外声明的契约，比如各种公共方法等。用户代码应该只跟这些契约有关，而不应该跟这些契约的实现有关。比如，抽象类A中定义了一个方法M，用户在声明变量时应该这样：&lt;span style="background-color: #cccccc;"&gt;A a = &amp;hellip;&lt;/span&gt;，在调用时是这样：&lt;span style="background-color: #cccccc;"&gt;a.M()&lt;/span&gt;。用户代码所关心的问题就是调用A定义的M，而不用理会究竟是子类C1的M，还是C2的M，这样，用户代码就跟具体的实现解耦了。&lt;/p&gt;&lt;p&gt;然而我们必须要知道，《设计模式》这本书是针对C++这门语言的，而C++没有C#中的接口这个概念。在C#和Java里，接口是和抽象类差不多同一层次的抽象，它仅仅提供契约，而不提供任何默认实现。所以对于接口IA，声明时和调用时采用这样的代码：&lt;span style="background-color: #cccccc;"&gt;IA a = &amp;hellip;; a.M();&lt;/span&gt; 也同样是针对&lt;em&gt;接口&lt;/em&gt;编程。这不应该有任何异议吧？&lt;/p&gt;&lt;p&gt;现在回到我之前的观点：将方法的返回类型设计为接口，是否是针对&lt;em&gt;接口&lt;/em&gt;编程的一部分？我们来看代码&lt;/p&gt;&lt;span style="color: blue;"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;IBar&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;void &lt;/span&gt;N();&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;Bar &lt;/span&gt;: &lt;span style="color: #2b91af;"&gt;IBar&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public void &lt;/span&gt;N(){}&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;Foo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;IBar &lt;/span&gt;M()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Bar&lt;/span&gt;();&lt;br/&gt;    }&lt;br/&gt;}&lt;p&gt;在用户代码中，我们可以这样声明一个IBar：&lt;/p&gt;&lt;span style="color: #2b91af;"&gt;IBar &lt;/span&gt;bar = &lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt;.M();&lt;p&gt;我在CSDN的帖子里指出，如果Foo的M方法返回一个Bar，那么用户在声明变量的时候仍然使用IBar bar = Foo.M()是没有任何意义的，因为已经明确知道M返回的是具体类型了。现在想想其实也是有意义的。至少在API改变的时候，如以后将M的返回值改成IBar或其他实现了IBar的类时，客户代码不需要修改。这也是针对&lt;em&gt;接口&lt;/em&gt;编程的一个意义所在。&lt;/p&gt;&lt;p&gt;那么我们在设计API的时候让M返回IBar而不是Bar，这样做的意义何在呢？我们可以强制用户在声明变量的时候使用IBar bar而不是Bar bar，从而避免由于M的实现修改后（比如返回了另一个实现了IBar的类）造成客户端代码无法编译的情况。因此我说，返回接口，也是针对&lt;em&gt;接口&lt;/em&gt;编程的一部分。事实上上面所描述的《设计模式》这本书中关于针对&lt;em&gt;接口&lt;/em&gt;编程的第三点&amp;mdash;&amp;mdash;实例化变量的时候使用创建型模式，就是这个意思。 &lt;br /&gt;不知道我说明白了没有，列位看明白了没有。对于面向接口编程，我也搜到了很多帖子，希望对大家有帮助：&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/1992384/program-to-an-interface-what-does-it-mean"&gt;http://stackoverflow.com/questions/1992384/program-to-an-interface-what-does-it-mean&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/1413543/what-does-it-mean-to-program-to-a-interface"&gt;http://stackoverflow.com/questions/1413543/what-does-it-mean-to-program-to-a-interface&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface"&gt;http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/9249832/interface-segregation-principle-program-to-an-interface"&gt;http://stackoverflow.com/questions/9249832/interface-segregation-principle-program-to-an-interface&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.artima.com/lejava/articles/designprinciples.html"&gt;http://www.artima.com/lejava/articles/designprinciples.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;另外我还在Stack Overflow上单独开了一贴，询问返回接口是否能与针对接&lt;em&gt;口&lt;/em&gt;编程挂钩，也有人说我对&amp;ldquo;针对&lt;em&gt;接口&lt;/em&gt;编程&amp;rdquo;有误解，不过我觉得他也没明白我的意思，我当然知道两种&amp;ldquo;接口&amp;rdquo;的不同啦：）&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/9598441/should-the-return-type-of-a-method-declaration-be-interface-or-concrete-class"&gt;http://stackoverflow.com/questions/9598441/should-the-return-type-of-a-method-declaration-be-interface-or-concrete-class&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2385200.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2012/03/08/should-method-return-interface-or-concrete-class-and-programming-to-an-interface.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2012/02/08/my2011.html</id><title type="text">我的2011</title><summary type="text">十五也终于过完了，这个年算是结束了，节后综合症也该痊愈了，该开始执行一年的学习和工作计划了。就从去年的总结开始吧。这当然是一份迟到的年终总结。过去的一年对我来说实在是太重要了，以至于我多次因为懒惰想放弃总结，却最终因为不舍而提起笔来。</summary><published>2012-02-08T06:58:00Z</published><updated>2012-02-08T06:58:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2012/02/08/my2011.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2012/02/08/my2011.html"/><content type="html">&lt;p&gt;十五也终于过完了，这个年算是结束了，节后综合症也该痊愈了，该开始执行一年的学习和工作计划了。就从去年的总结开始吧。这当然是一份迟到的年终总结。过去的一年对我来说实在是太重要了，以至于我多次因为懒惰想放弃总结，却最终因为不舍而提起笔来。&lt;/p&gt;  &lt;p&gt;11年1月，在《&lt;a href="http://www.ituring.com.cn/book/36"&gt;C#与.NET 4高级程序设计&lt;/a&gt;》交稿之后几天，我正式接受了翻译《&lt;a href="http://www.amazon.com/C-Depth-Second-Jon-Skeet/dp/0935715010/"&gt;C# in Depth 2nd Edition&lt;/a&gt;》的邀请。翻译这本书是需要很大的勇气的。一方面，我读过原版，英文的复杂程度远超出了我的能力范围。之前翻译的《&lt;a href="http://www.ituring.com.cn/book/36"&gt;C#与.NET 4高级程序设计&lt;/a&gt;》和《ASP.NET 3.5揭秘》都属于很浅显的英文，翻译起来没有任何难度，最快时一天可以完成15页。而这本则不同。后来我最快一天也就5页，大多数情况下一天能啃下1页来就算不错了，这也直接延误了出版。另一方面，&lt;a href="http://www.cnblogs.com/kirinboy/archive/2010/12/30/my2010.html"&gt;妻子身怀六甲&lt;/a&gt;，而且有先兆流产征兆，亟需照顾。我这个时候接受一份难度很大的翻译工作，说实话是很不负责任的。但最终，“自私”战胜了责任。这是一本非常牛逼的C#书籍，为了能在这样一本牛逼书的中文版上留下自己的名字，我毅然决然地接受了挑战。&lt;/p&gt;  &lt;p&gt;接下来的几个月里，在每个夜晚老婆睡觉以后，我便独自躲在小屋里开始翻译。由于没有电脑（那段时间住在丈母娘家），我只能对照着打印出来的原文，在纸上写译文。遇到不懂的词，就用手机上网查。这样，每天都要翻译到凌晨一两点钟，然后再看一些闲书入眠。第二天到了公司，再将前一晚的译文抄到文档里。（这些纸可要妥善保存，万一哪天有人质疑这不是我翻译的，还能拿出来自证。）在如此恶劣的翻译条件下，在超出合同规定的交稿期限130%之后，我终于把最终版交给了图灵的编辑。这已经是8月份的事了。&lt;/p&gt;  &lt;p&gt;12月底，《&lt;a href="http://www.ituring.com.cn/book/763"&gt;深入理解C#（第二版）&lt;/a&gt;》终于上市了，经过了一系列的微博轰炸，据说销量还不错。这让我十分欣慰，感觉大半年的辛苦没有白费。能够让更多的人读到这本好书，让它不像上一版那样被埋没，付出再多也觉得值得。&lt;/p&gt;  &lt;p&gt;相比而言，4月份出版的《C#与.NET 4高级程序设计（第5版）》就卖的没那么好了。虽然这本书翻译时不那么费劲，但新增的部分实在太多了，最后我不完全统计，差不多有20万中文。这本书有1200多页，翻译、编辑都痛不欲生。想必读者在阅读时可能也会有这样的感觉，导致很多人建议分成上下两册出版。&lt;/p&gt;  &lt;p&gt;8月份，在我交稿后的10个小时后，女儿珧珧出生了。这个只有5斤7两的小天使，给全家带来了无尽的欢乐和忙碌。珧珧妈虽然是顺产，但却生完之后却承受了常人没有的痛苦和折磨。先是胎盘粘连，两个星期之内先后做了两次清宫术，接着是耻骨联合分离，整整一个月都只能在床上吃喝拉撒。在11年8月底9月初的这段时间里，我的爱人经历了一次人生的洗礼。康复之后，她蜕变成一个完美的母亲，承担起照顾宝宝的重任。&lt;/p&gt;  &lt;p&gt;晋升为父亲之后，我也感受到了前所未有的压力。首先就是经济上的，公司的这点薪水完全支付不起宝宝的奶粉衣服纸尿裤。其次是生活上的，作为一个笨手笨脚没什么生活经验的大老粗，我完全没法照顾孩子，尽管空有一腔热血。现在的情况基本是，晚上回家吃完饭后，刷碗扫地拖地，刷奶瓶消毒，半夜起来给宝宝冲一次奶，这就是我一天全部的家务和育儿工作。&lt;/p&gt;  &lt;p&gt;在工作方面，这两年一直在跟遗留系统打交道。面对坏味道比比皆是，几乎没有单元测试的旧代码，你必须加倍小心。幸好上半年终于可以在旧系统上加新功能了，至少也算是写了些新的代码。下半年组内筹划了一个新的系统，虽然系统是新的，但仍要使用JDK1.4，写起来仍然很痛苦。&lt;/p&gt;  &lt;p&gt;这一年看过的书有&lt;/p&gt;  &lt;p&gt;&lt;img src="http://img3.douban.com/spic/s4546495.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4270619.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s4599081.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4690073.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4349249.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s4546872.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s1670658.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4669554.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s6089492.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s6920345.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s3190162.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s1689688.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4702048.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s6783948.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4911906.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4477716.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4509883.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s2170219.jpg" /&gt;&lt;/p&gt;  &lt;p&gt;看了两眼就放下的书有&lt;/p&gt;  &lt;p&gt;&lt;img src="http://img1.douban.com/spic/s3784022.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4561187.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4241556.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4549954.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4692124.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4702437.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4391754.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4656028.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s5917529.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s4387251.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s1085745.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s3923505.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s3291788.jpg" /&gt;&amp;#160; &lt;img src="http://img3.douban.com/spic/s4476524.jpg" /&gt;&amp;#160; &lt;img src="http://img1.douban.com/spic/s2690732.jpg" /&gt;&lt;/p&gt;  &lt;p&gt;至于买的书，那就太多了，就不一一列举了。京东两次促销，先后购入了差不多1k的书，再加上从图灵那里“搜刮”来的，得有将近100本了。看书的速度还是太慢，永远赶不上买书的速度。家里的书柜也基本上快满了，以后换了大房子，一定要准备一间书房，四面都摆满书柜。&lt;/p&gt;  &lt;p&gt;这就是我2011年的总结，简单地说就是，译了一本牛逼书，生了一个漂亮妞儿。&lt;/p&gt;  &lt;p&gt;12年的计划如下：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;1月初红色星期五的时候买了一台Mac Pro，这下要好好学习iOS开发了。目前已经有了几个idea，等开发者帐号申请下来就开始慢慢搞。 &lt;/li&gt;    &lt;li&gt;系统地学习一下JavaScript。以前一直没有系统学习过，现在不会JavaScript你都不好意思跟人打招呼。 &lt;/li&gt;    &lt;li&gt;.NET Framework 4.5发布后，要及时跟进。以前翻译的书如果有了新版本，也要及时翻译。 &lt;/li&gt;    &lt;li&gt;要自己做些项目，目前有3个想法，能实现几个就实现几个吧。 &lt;/li&gt;    &lt;li&gt;感觉看的书还是太少了，要多看些书。 &lt;/li&gt;    &lt;li&gt;减肥。争取在8月份宝宝一周岁的时候，把体重控制在75kg左右。今天的毛重是82.1kg。 &lt;/li&gt;    &lt;li&gt;在&lt;a href="http://blog.sina.com.cn/kirinboy"&gt;麒麟.Life&lt;/a&gt;上写些育儿经。 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;再见，2011，尽管你早已过去。&lt;/p&gt;  &lt;p&gt;Come on，2012，我将全力以赴。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2342723.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2012/02/08/my2011.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/12/28/the-differences-between-in-depth-and-in-action.html</id><title type="text">In Depth和In Action的区别——写在《深入理解C#（第二版）》出版之际</title><summary type="text">Manning出版社出版的很多图书，都用XXX in Action这样的方式来命名，如著名的Ajax in Action、专门介绍LINQ的LINQ in Action，以及jQuery in Action、PHP in Action等等。这些书偏重基础，并包含大量的代码示例，即使是初学者，读起来也会十分轻松。</summary><published>2011-12-28T04:46:00Z</published><updated>2011-12-28T04:46:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/12/28/the-differences-between-in-depth-and-in-action.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/12/28/the-differences-between-in-depth-and-in-action.html"/><content type="html">本文在《&lt;a href="http://www.ituring.com.cn/book/763"&gt;深入理解C#（第二版）&lt;/a&gt;》译者序的基础之上进行了一些删改&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border-width: 0px;" title="深入理解C#（第2版）" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201112/201112281245361877.jpg" alt="深入理解C#（第2版）" width="384" height="484" align="right" border="0" /&gt;&lt;/p&gt;&lt;p&gt;Manning出版社出版的很多图书，都用XXX in Action这样的方式来命名，如著名的Ajax in Action、专门介绍LINQ的LINQ in Action，以及jQuery in Action、PHP in Action等等。这些书偏重基础，并包含大量的代码示例，即使是初学者，读起来也会十分轻松。我们一般称这种书为入门书，图灵公司在引进的时候，也给它们起了一个恰如其分的中文名：实战。如《Ajax实战》、《LINQ实战》等等。&lt;/p&gt;&lt;p&gt;然而这本书则不同，它的英文名不是C# in Action，而是C# in Depth。这in Depth和in Action有什么区别呢？&lt;/p&gt;&lt;p&gt;很多C#程序员在有了一定基础之后，会出现一个成长的瓶颈。他们觉得似乎了解了C#的基本语法和各种语言特性，但对于这些特性的演变以及它们之间的关联却知之甚少。他们会在代码中使用泛型集合，但是对于类型推断的规则似乎还很模糊；他们经常使用foreach语句，但却无法自如地使用yield；他们知道C# 3中增加了很多非常酷的语法糖，但却不知道这些语法糖实际上都是为了最酷的LINQ准备的；他们为C# 4提供了动态类型而欢欣鼓舞，但却不了解DLR如何实现动态绑定，并且往往会滥用dynamic。这时候，他们需要一本书，一本能对C#的每个特性进行透彻分析的书，一本能指引他们走向正确道路的书。他们不需要一本C# in Action，因为他们已经熟悉了字符串和整型，已经会编写接口、类、方法、属性和字段，甚至能说出引用类型和值类型的区别。他们需要的是一本进阶书，一本深入讲解C#的书。而现在您手上的，正是这样一本书。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;这就是in Depth和in Action的区别！&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;本书没有任何关于.NET平台和CLR的内容，也不会指导你如何创建WPF或ASP.NET应用程序，它将全部注意力都放到C#语言本身，着重解析了C#各个版本的进化和演变。它面向中高级C#程序员，如果您只是初学者，那它并不适合您。正如老赵所说，&lt;a href="http://weibo.com/1560442584/xDXaB5nLW"&gt;这本书中肯定有一半以上是你不知道的东西&lt;/a&gt;。而且我觉得，&lt;span style="color: #000000;"&gt;&lt;strong&gt;书中的每一段代码，都可以作为一道面试题&lt;/strong&gt;&lt;/span&gt;，如果您打算招聘一位高级.NET工程师，不妨参考书中的示例。&lt;/p&gt;&lt;p&gt;在本书英文版刚刚问世时，就得到了业界诸多大牛的肯定和推荐。当图灵的编辑问我是否有兴趣翻译第二版的新增内容时，我恰好刚刚阅读完第一版的中文版，正处于余香绕齿的阶段，于是毫不犹豫地就答应了下来。&lt;/p&gt;&lt;p&gt;第二版新增了三个大的章节（分别介绍了C# 4的新增特性和代码契约），并对迭代器和LINQ等内容进行了修订。说实话，我的工作量并不算多，但从开始翻译到最后交付，总共持续了八个多月（一月份签约，八月份交稿，后续还进行了一些修改），直接导致本书的上市推迟了将近半年，在此要向各位读者致歉。之所以翻译得慢，除了我自身的懈怠以外，本书的英文原文也并不像其他技术书籍那样浅显易懂，其中有很多暗语和弦外之音，如果我由于水平有限而没能参透其中的含义，请各位读者批评指正。&lt;/p&gt;&lt;p&gt;周靖和&lt;a href="http://weibo.com/heavenwing"&gt;朱永光&lt;/a&gt;两位老师为第一版的翻译付出了艰辛的劳动，在他们打下的良好基础之上进行工作，让我感觉踏实了不少。我还要感谢老赵为本书进行复审，如果没有他的修改意见，您一定会对这本书失望有加。&lt;/p&gt;&lt;p&gt;最后，祝朋友们阅读愉快！希望您在学习编程这条永无止境的道路上，&lt;strong&gt;不仅in Action，更要in Depth&lt;/strong&gt;！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2304627.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/12/28/the-differences-between-in-depth-and-in-action.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/12/23/eclipse-tips-3-templates.html</id><title type="text">Eclipse Tips（3）：Template</title><summary type="text">Eclipse的Template实在是太强大了，这是我最近才体会到的。以前一直没有发现，或者说没有在意，但是现在看来，Template使得Eclipse的代码编辑功能在某种程度上超越了Visual Studio。</summary><published>2011-12-23T05:33:00Z</published><updated>2011-12-23T05:33:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/12/23/eclipse-tips-3-templates.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/12/23/eclipse-tips-3-templates.html"/><content type="html">&lt;p&gt;Eclipse的Template实在是太强大了，这是我最近才体会到的。以前一直没有发现，或者说没有在意，但是现在看来，Template使得Eclipse的代码编辑功能在某种程度上超越了Visual Studio。比如，我们在代码编辑器中输入sysout，马上就会弹出一个名为sysout的模板&lt;/p&gt;  &lt;p&gt;&lt;img style="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/kirinboy/201112/201112231333068766.png" width="244" height="58" /&gt;&lt;/p&gt;  &lt;p&gt;点击或回车或Alt + /，编辑器就会自动插入这样的代码&lt;/p&gt;  &lt;p&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/kirinboy/201112/20111223133306195.png" width="166" height="28" /&gt;&lt;/p&gt;  &lt;p&gt;这对于十分冗长的Java代码来说，无异于雪中送炭。&lt;/p&gt;  &lt;p&gt;打开Preferences，在Java—&amp;gt;Editor—&amp;gt;Templates中，可以看到自带的模板。比较常用的有if、ifelse、try、runnable等等。&lt;/p&gt;  &lt;p&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/kirinboy/201112/201112231333077785.png" width="644" height="465" /&gt;&lt;/p&gt;  &lt;p&gt;如图所示，在C#中我们编写一个Lambda是很轻松的事情，但是在Java中手写Runnable就很痛苦了，现在有了代码模板，您是否觉得工作量减轻了不少呢？&lt;/p&gt;  &lt;p&gt;以下是一些链接，可以自定义一些有用的模板：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://eclipse.dzone.com/news/effective-eclipse-custom-templ"&gt;Effective Eclipse: Custom Templates&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://stackoverflow.com/questions/1028858/useful-eclipse-java-code-templates"&gt;Useful Eclipse Java Code Templates&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2299306.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/12/23/eclipse-tips-3-templates.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/12/20/2294884.html</id><title type="text">FROM WAS7/JDK5 TO WAS6/JDK4</title><summary type="text">手头的项目目前是JDK4+WAS6，为了能用JDK5来开发，需要使用Retrotranslator将JDK5编写的代码转换为JDK4。你知道，没有泛型、迭代器、Annotation、自动装拆箱等语法特性，开发Java就恶上加恶了。以下是搜集的一些资料，先贴在这里，以防丢失。是否能真的使用J5，还不得而知，上帝保佑吧。</summary><published>2011-12-20T08:48:00Z</published><updated>2011-12-20T08:48:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/12/20/2294884.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/12/20/2294884.html"/><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;手头的项目目前是JDK4+WAS6，为了能用JDK5来开发，需要使用Retrotranslator将JDK5编写的代码转换为JDK4。你知道，没有泛型、迭代器、Annotation、自动装拆箱等语法特性，开发Java就恶上加恶了。以下是搜集的一些资料，先贴在这里，以防丢失。是否能真的使用J5，还不得而知，上帝保佑吧。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;strong&gt;WebSphere6+Struts2+Spring2+Hibernate3使用总结&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;原文地址：&lt;a href="http://www.zxbc.cn/html/20081215/68967.html"&gt;http://www.zxbc.cn/html/20081215/68967.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;项目在开发时使用JDK5+MyEclipse5.5+Tomcat6环境、Struts2+Spring2+Hibernate3框架以及DWR和E3 Tree技术。项目准备打包部署时客户说要部署在WebSphere6.0服务器上，那时我的头真大了，听说用WebSphere很麻烦，而且又是WebSphere6.0，WebSphere6.0只支持JDK1.4，我的项目用到了Struts2和JDK5的新特性啊，真是疯了，一直抱怨着客户无事找事折磨我们。 &lt;br /&gt;总结一点还是我经验不足，遇事不够冷静，没认真分析，害怕麻烦，导致我走了好多弯路，浪费了好多时间，现在与大家分享一下，以免大家再次犯此类错误。 &lt;br /&gt;首先，明确WebSphere的版本。确定WebSphere6.0对环境的要求，这一点很重要，我就栽在这点上。WebSphere6.0的环境是JDK1.4，Servelet2.4、JSP2.0，清楚了这点后再考虑其他的问题。 &lt;br /&gt;第二，WebSphere6.0只支持IBM自带的JDK1.4,我用JDK5开发的，那么关于JDK5的新特性必须改为JDK1.4的（其实新特性不改也行，只要用工具Retrotranslator将已经编译过的JDK5的CLASS转换为JDK1.4的CLASS，不过那样以后要是你修改项目的话，又要重新转换CLASS，那样会很麻烦，所以我还是修改了JDK5的新特性），再在MyEclipse中将项目的编译环境设置为JDK1.4的，安装的JDK版本不用改，可以继续用JDK5来开发。 &lt;br /&gt;第三，Struts2使用的开发环境是：JDK5、Servelet2.4、JSP2.0。这些都不冲突，关键是Struts2的架包是JDK5编译的，所以这是个问题，不过Struts2的开发者都为我们考虑到了，在struts2目录下的backport目录中提供了Retrotranslator转换工具，其中struts2-core-j4-2.0.11.1.jar和xwork-j4-2.0.4.jar已经转换好了，如果用到了Struts2的其他架包，你就要手工转换。架包的转换方法：在CMD中进入backport目录，再键入如：java -jar retrotranslator-transformer-1.2.2.jar -advanced -srcjar E:\GSLY\WebRoot\WEB-INF\lib\架包名 -destjar 新架包名。这样架包就可以转换为JDK1.4的了，再将backport目录中的backport-util-concurrent-3.0.jar、retrotranslator-runtime-1.2.2.jar和你转好的包扔到项目lib目录下，原来的删除即可。记住，只要你用到了Struts2的架包最好都要转换，以免出现其他麻烦。 &lt;br /&gt;第四，E3 Tree要求：Servelet2.4、JSP2.0。这个与WebSphere6.0不冲突。 &lt;br /&gt;第五，Web.xml里的配置要按照规范写，特别是元素的顺序问题，WebSphere对XML的要求很严，不像Tomcat，其余也没什么要求，我的项目现在都可以在WebSphere6。0上跑了，呵呵.... &lt;br /&gt;这方面网上的资料还是蛮多的，不明白的可以GOOGLE下，最重要的还是要搞清楚第一点，对症下药。虽然WebSphere的使用很麻烦，但客户喜欢，我们做开发的也没办法，只能依着他们，谁叫客户是上帝呢。嘿嘿，加油！ &lt;br /&gt;附注： &lt;br /&gt;WebSphere5.1：JDK1.4，Servelet2.3、JSP1.2 &lt;br /&gt;WebSphere6.0：JDK1.4，Servelet2.4、JSP2.0 &lt;br /&gt;WebSphere6.1：JDK5.0，Servelet2.4、JSP2.0 &lt;br /&gt;Tomcat4.1：JDK1.4，Servelet2.3、JSP1.2 &lt;br /&gt;Tomcat5.5：JDK5.0，Servelet2.4、JSP2.0 &lt;br /&gt;Tomcat5.5：JDK5.0，Servelet2.4、JSP2.0 &lt;br /&gt;Tomcat6.0：JDK5.0，Servelet2.5、JSP2.1 &lt;br /&gt;Struts2：JDK5.0，Servelet2.4、JSP2.0 &lt;br /&gt;E3 Tree：Servelet2.4、JSP2.0&lt;/p&gt;&lt;p&gt;&lt;strong&gt;项目从jdk1.5移植到jdk1.4&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;原文地址：&lt;a href="http://peony07.blogbus.com/logs/107368003.html"&gt;http://peony07.blogbus.com/logs/107368003.html&lt;/a&gt;，&lt;a href="http://bangzhuzhongxin.blogbus.com/logs/11205960.html"&gt;版权声明&lt;/a&gt;&lt;/p&gt;&lt;p&gt;进入项目组的时候，项目框架就已经搭好了，Struts2+spring2.5.6+ibatiS2.3.4+jdk1.5. 可能是以前一直用s1sh的架子，一直都很难接受ibatiS的配置模式，所以对这框架不怎么感冒。但是我是农民工嘛，说啥做啥呗。谁知项目都快要上线了，老大抛出一个雷，生产环境犹豫某些原因只能用jdk1.4......我勒个去！struts2&amp;nbsp; 默认需求就是jdk1.5，悲剧了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 要想应用JDK1.4,使用的主要的是Struts2.0的发行包里提供的J4目录中的Retrotranslator.利用它可以将原JDK5的包转化成JDK1.4的.关于Retrotranstator的介绍,可以查看&lt;a href="http://retrotranslator.sourceforge.net/"&gt;http://retrotranslator.sourceforge.net/&lt;/a&gt;,里面写的很详细.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在J4目录中,已经将Struts2.0基本的两个Jar文件转好了,分别是struts2-core-j4-2.0.9.jar和xwork-j4-2.0.4.jar.如果你的程序中还用到的其他的Jar包,可以通过脚本把Jar包转成J4版本的.我们的程序中用到了spring和ibatis两个Jar包,所以需要将这两个包转成J4的.执行以下命令之前需要把Retrotranslator-1.2.9-bin.zip下的文件解压到你的jdk1.5的bin目录下。&lt;/p&gt;&lt;p&gt;java -jar retrotranslator-transformer-1.2.9.jar -advanced -srcjar D:\lib\spring-framework-2.5.6.jar -destjar D:\lib\j1.4\spring-framework-j4-2.5.6.jar；java -jar retrotranslator-transformer-1.2.9.jar -advanced -srcjar D:\lib\ibatis-2.3.4.726.jar -destjar D:\lib\j1.4\ibatis-j4-2.3.4.jar;&lt;/p&gt;&lt;p&gt;转换之后把新的包加载进系统，再将J4目录中的retrotranslator-transformer-1.2.2.jar, backport-util-concurrent-3.0.jar和retrotranslator-runtime-1.2.2.jar一起放到WEB- INF/lib下.并修改新工程的编译级别为1.4。当然项目中用到的jdk1.5的特性都是需要手动修改的，我们系统中用到了大量的泛型，以及一些循环，额，改起来比较费劲，足足改了一上午。 然后启动tomcat，还是报错，进入tomcat的启动日志看，发现还有一些用到的插件包需要转换，&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; java -jar retrotranslator-transformer-1.2.9.jar -advanced -srcjar D:\lib\struts2-convention-plugin-2.1.8.1.jar -destjar D:\lib\j1.4\struts2-convention-plugin-j4-2.1.8.1.jar;&amp;nbsp; java -jar retrotranslator-transformer-1.2.9.jar -advanced -srcjar D:\lib\struts2-spring-plugin-2.1.8.1.jar -destjar D:\lib\j1.4\struts2-spring-plugin-j4-2.1.8.1.jar;&amp;nbsp; java -jar retrotranslator-transformer-1.2.9.jar -advanced -srcjar D:\lib\jsonplugin-0.34.jar -destjar D:\lib\j1.4\jsonplugin-j4-0.34.jar;&lt;/p&gt;&lt;p&gt;一次次的调试，重启了3次&amp;middot;&amp;middot;&amp;middot;&amp;middot;最后终于不报错了。tomcat5.0+jdk1.4.2测试通过。&lt;/p&gt;&lt;p&gt;PS：项目做到这种地步，哎&amp;middot;我都不说什么了。不过这次的问题是由我来解决的，个人还是比较有成就感的，因为没有经验，开始时心里是没底的，硬着头皮上，最后摸摸索索，还是给整出来了。所以觉得再烂的项目，也有值得你学习的地方，值得你认真对待的方面，没有试过怎会知道结果呢。老大一直想我把业务这一块把控起来，我比较懒，怕麻烦，一直在推托，现在想想，也许是时候踏出那一步了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Retrotranslator--将JDK5.0项目完全转换为JDK1.4 字节码的恩物&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;原文地址：&lt;a href="http://www.blogjava.net/calvin/archive/2006/04/27/43443.html"&gt;http://www.blogjava.net/calvin/archive/2006/04/27/43443.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;因为&lt;a href="http://retrotranslator.sf.net/"&gt;Retrotranslator&lt;/a&gt;的出现，&lt;a href="http://www.springside.org.cn/"&gt;SpringSide&lt;/a&gt;终于放心升到JDK5.0，只要用户在build的时候选择war14 task，生成的war就保证仍然100%运行在JDK1.4的服务器上。在最新的retrotranslator 1.0.7 支持下，SpringSide在Tomcat 5.0+JDK1.4上部署成功。 &lt;br /&gt;不能随意更改运行环境JDK的历史项目，客户真金白银买了不支持JDK5的Weblogic8.1的项目，一般只能看着JDK5的annotation、泛型和EJB3干咽口水，所以上帝說要有光，我们有了这个恩物。 &lt;br /&gt;和以前推荐的&lt;a href="http://retroweaver.sourceforge.net/"&gt;Retroweaver&lt;/a&gt;一样，&lt;strong&gt;大家直接用JDK5开发&lt;/strong&gt;，如果需要部署到JDK1.4的运行环境，就通过asm把Class转到JDK1.4的字节码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;但它不仅支持JDK5的新语法，还大量支持JDK5的新增API。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Retrotranslator的用法很简单，可以用命令行、Ant和IDEA插件自动转换，&lt;a href="http://retrotranslator.sf.net/"&gt;&lt;span style="text-decoration: underline;"&gt;http://retrotranslator.sf.net&lt;/span&gt;&lt;/a&gt; 上讲得很清楚，可以转换Jar，也可以转换Class目录。 &lt;br /&gt;比较特别的是有个Verify选项，能确保你没有用到它暂时还不支持的JDK5 API（记得Classpath里要加入JDK1.4的rt.jar)。 &lt;br /&gt;&lt;strong&gt;附：springside war14 任务简述&lt;/strong&gt; &lt;br /&gt;war14在打包时，会调用&lt;a href="http://svn.javascud.org/svn/springside/trunk/misc/jdk14/build.xml"&gt;/misc/jdk14/build.xml&lt;/a&gt;, 为drools,compas,easymock2等几个使用了JDK1.5技术的jar 生成jdk1.4的版本，并为项目的classes 目录生成JDK1.4的版本，然后用它们替换war中原来的内容即可。&lt;/p&gt;&lt;p&gt;注意用户可能要自己在/misc/jdk14/build.properties中设一下jdk1.4的路径。&lt;/p&gt;&lt;p&gt;build.xml 片断：&lt;/p&gt;&lt;p&gt;&amp;lt;target name="jdk14src"&amp;gt; &amp;lt;taskdef name="retrotranslator" classpathref="compile.classpath"&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; classname="net.sf.retrotranslator.transformer.RetrotranslatorTask"/&amp;gt; &lt;br /&gt; &amp;lt;retrotranslator destdir="classes" verify="true"&amp;gt; &amp;lt;src path="http://www.cnblogs.com/springside-bookstore/webapp/WEB-INF/classes"/&amp;gt; &amp;lt;classpath location="${jdk14_home}/lib/rt.jar"/&amp;gt; &amp;lt;classpath refid="compile.classpath"/&amp;gt; &amp;lt;/retrotranslator&amp;gt; &lt;br /&gt;&amp;lt;/target&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;利用Retrotranslator将Jdk1.5项目迁移到1.4&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;原文地址：&lt;a href="http://txxm.iteye.com/blog/59612"&gt;http://txxm.iteye.com/blog/59612&lt;/a&gt;&lt;/p&gt;&lt;p&gt;项目之初，考虑到主流应用服务器大都开始支持Jdk1.5，另外一些开源库也要1.5才能运行，所以Jdk决定采用1.5版本。1.5的新特性确实很爽，呵呵。等到项目快结束的时候，又要求支持1.4，理由是用户现有服务器有可能不支持1.5。代码改成支持1.4，不仅浪费时间，而且还要放弃1.5的特性。看到网上介绍Retrotranslator，感觉不错，今天试用了一下，结果相当满意，tomcat5.0 + jdk1.4 将我的应用跑了起来，呵呵。&lt;/p&gt;&lt;p&gt;下面我将操作步骤记录下来：&lt;/p&gt;&lt;p&gt;1、在Jdk1.5下编译java源文件（这时的class只能在1.5下跑）；&lt;/p&gt;&lt;p&gt;2、下载Retrotranslator，我用的是1.2.1版，解压后可得到三个jar，retrotranslator-transformer-1.2.1.jar、backport-util-concurrent-3.0.jar、retrotranslator-runtime-1.2.1.jar；Retrotranslator可以命令行、ant或maven任务、Intellij idea plugin方式运行，下面以ant任务方式运行；&lt;/p&gt;&lt;p&gt;3、参考以下ant脚本（附件），需要修改相应部分：&lt;/p&gt;&lt;p&gt;(注：该脚本不仅转换classes目录下的class文件，而且还转换1.5下发布的jar，如：hibernate-annotations-3.2.1.ga.jar，生成相应的1.4版本。)&lt;/p&gt;&lt;p&gt;4、在jdk1.4环境下（例如tomcat5.0+jdk1.4环境），用1.4版本的jar替换原有的jar，用转换后的class替换原有的class；&lt;/p&gt;&lt;p&gt;5、将backport-util-concurrent-3.0.jar、retrotranslator-runtime-1.2.1.jar添加到WEB-INF/lib目录；&lt;/p&gt;&lt;p&gt;6、启动tomcat，不出问题的话，应该能跑起来！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2294884.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/12/20/2294884.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/11/24/asp-net-mvc-4-roadmap.html</id><title type="text">ASP.NET MVC 4路线图</title><summary type="text">一年的时光悄然而逝，又到了快发布ASP.NET MVC新版本的时候了。本文档涵盖了ASP.NET MVC 4框架的高级路线图。我们正处于开发ASP.NET MVC 4的早期阶段，而这份路线图是下一版本的计划文档，清楚这一点是十分重要的。它并不是新特性的规范。我们希望能够实现这里列出的大多数或所有特性，但却无法保证。计划可能会发生变化，你也可以协助我们改变计划！请访问Uservoice网站来提交反馈，这样我们就能清楚地知道你希望新版本包含哪些内容。</summary><published>2011-11-24T05:27:00Z</published><updated>2011-11-24T05:27:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/11/24/asp-net-mvc-4-roadmap.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/11/24/asp-net-mvc-4-roadmap.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;a name="OLE_LINK6"&gt;&lt;/a&gt;原文地址：&lt;a href="http://aspnet.codeplex.com/wikipage?title=ASP.NET%20MVC%204%20RoadMap"&gt;http://aspnet.codeplex.com/wikipage?title=ASP.NET%20MVC%204%20RoadMap&lt;/a&gt;&lt;/p&gt;&lt;p&gt;本文首发于&lt;a href="http://www.ituring.com.cn/article/438"&gt;图灵社区&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;一年的时光悄然而逝，又到了快发布ASP.NET MVC新版本的时候了。本文档涵盖了ASP.NET MVC 4框架的高级路线图。&lt;/p&gt;&lt;p&gt;我们正处于开发ASP.NET MVC 4的早期阶段，而这份路线图是下一版本的计划文档，清楚这一点是十分重要的。它并不是新特性的规范。我们希望能够实现这里列出的大多数或所有特性，但却无法保证。计划可能会发生变化，你也可以协助我们改变计划！请访问&lt;a href="http://aspnet.uservoice.com/forums/41201-asp-net-mvc"&gt;Uservoice网站&lt;/a&gt;来提交反馈，这样我们就能清楚地知道你希望新版本包含哪些内容。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ASP.NET MVC 4&lt;/strong&gt;&lt;strong&gt;开发者预览版已经可以使用了！&lt;/strong&gt;要了解此版本的更多信息，请访问&lt;a href="http://www.asp.net/mvc/mvc4"&gt;ASP.NET MVC 4页面&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;通过Web Platform installer安装&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.microsoft.com/web/gallery/install.aspx?appid=MVC4VS2010&amp;amp;prerelease=true"&gt;ASP.NET MVC 4 for Visual Studio 2010&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.microsoft.com/web/gallery/install.aspx?appid=MVC4VS11&amp;amp;prerelease=true"&gt;ASP.NET MVC 4 for Visual Studio 11 Developer Preview&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;或者如果你想直接下载安装器，可以访问&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=1366879f-feea-420d-9c8c-38253b86d10c"&gt;下载详细页面&lt;/a&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;strong&gt;ASP.NET MVC&lt;/strong&gt;&lt;strong&gt;成为最优秀的构建现代富Web&lt;/strong&gt;&lt;strong&gt;应用程序的平台。&lt;/strong&gt;因此我们关注ASP.NET MVC 4中的特性（以及整个Web堆栈），这可以使我们离这个目标更近一些。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;主题&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在计划特殊的特性之前，ASP.NET小组制定出了一些主题，来指导我们的计划。有些主题并不特定于ASP.NET MVC的，因此无法在ASP.NET MVC特性小组中单独实现。我们将与微软以及微软以外的人士合作，来实现这些目标。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;开发和部署：使开发和部署的流程更加简单、优秀、快速。&lt;/li&gt;&lt;li&gt;利用平台：Razor视图引擎以及ASP.NET MVC 3中一些新的辅助器也可用于ASP.NET Web页面。我们将在ASP.NET MVC中继续利用整个Web平台中的共享特性。&lt;/li&gt;&lt;li&gt;Ajax：无论是向现有Web应用程序中添加Ajax，还是实现一个完整的单页应用程序（如Gmail），我们都将改进ASP.NET MVC中的Ajax开发。我们已经有了一些想法，但现在正处于构建应用程序以暴露和了解那些可以修复的bug这一过程之中。&lt;/li&gt;&lt;li&gt;HTML 5、平板和移动设备：通过简单地构建一个HTML 5 Web应用程序，来构建平板和移动应用程序，已经成为了产业趋势。HTML 5应用程序提供了最广泛的分布选择，可以运行于各种各样的设备之中。但编写面向移动和平板设备的应用程序引擎则需要丰富的经验。我们希望构建这种应用程序可以变得更加简单。&lt;/li&gt;&lt;li&gt;云：我们要将在云上（如Windows Azure）部署和承载Web应用程序的任务变得更加简捷。为了从云中受益，我们将关注于性能、安全和可扩展性。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;现在，要开始介绍你最感兴趣的部分了&amp;mdash;&amp;mdash;特性！注意，有些特性比其他的要更加丰满。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Recipses （基于任务的可扩展工具）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;有些任务要求你操作应用程序的多个部分。例如，要向视图中添加一个Ajax网格，需要生成视图代码来呈现网格的HTML标记，创建数据访问类来展示网格，添加控制器类使得Ajax网格可以通过异步调用来获取数据。&lt;/p&gt;&lt;p&gt;ASP.NET MVC 4 recipe是通过NuGet发布的一个对话框，它包含相关的用户界面以及用来自动执行某个特殊任务的代码。比如，实现一个基于OAuth的认证永远要比调用一个方法复杂得多，因为它需要很多设置和很多UI。而实现OAuth认证的recipe可能会提供一个UI，供你进行设置，然后生成所有需要的代码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;以下是一些可以使用recipe实现的想法：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Ajax网格&lt;/li&gt;&lt;li&gt;实现基于OAuth的认证&lt;/li&gt;&lt;li&gt;支持使用Windows Identity Framework的基于声明的认证&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;编写、部署和安装Recipe&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;要编写一个recipe，只需要实现一个使用了recipe API的对话框。该对话框包含一个MVC项目接口的实例，用起来比EnvDTE.DTE（用来自动化Visual Studio中的任务）要简单得多。&lt;/p&gt;&lt;p&gt;例如，要向一个ASP.NET MVC项目的某个area中添加一个controller，使用DTE可能需要调用多个方法，而recipe API则只需调用一个方法。&lt;/p&gt;&lt;p&gt;编写完这个对话框之后，将其打包成NuGet包，这样大家就可以用你的食谱（recipe）来做菜了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Recipe实物模型&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;下面这个实物模型展示了recipe是如何工作的。要启动一个recipe，可以在Solution Explorer中（或适当的文件中；一些recipe是位于上下文中的）右击项目节点，选择Run Recipe。这将打开一个菜单，有很多recipe可供选择。（这也可能是Run Recipes上下文菜单选项的子菜单。）&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image002" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327207269.jpg" alt="clip_image002" width="237" height="316" border="0" /&gt;&lt;/p&gt;&lt;p&gt;用NuGet安装的recipe都会显示在列表中。选中一个并启动recipe。不同的recipe具有不同的UI。&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image004" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327225992.jpg" alt="clip_image004" width="563" height="233" border="0" /&gt;&lt;/p&gt;&lt;p&gt;Recipe可以简单到只有一个对话框（理论上也可以一个对话框都没有），也可以是包含多个步骤的向导。点击Finish，使用你指定的设置运行recipe。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Recipe API&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;对于API来说，其理念是，recipe开发者可以获取项目接口的实例，该接口包含如何启动recipe的上下文。它还将在MVC项目系统之上提供一个简单易用的fa&amp;ccedil;ade，开发者不必学习整个接口的DTE集合。不过，接口还是可以访问DTE，以防止项目接口可能不够充分。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;内置的Recipe&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;作为该项目的一部分，我们计划构建一些内置的recipe。如前面提到的OAuth支持、Ajax网格、WIF。我们也在寻找其他的想法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;移动支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;移动设备（手机和平板）从可以浏览网站之后就开始愈发流行了。因此要为公众建立一个网站，你需要考虑能够为使用小屏幕或可触屏的访问者提供什么样的体验。在ASP.NET MVC 4中，我们希望为你提供直接却灵活的方式，实现一流的移动支持，不管你是创建新网站，还是增强已有的站点。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;默认模板的改变&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们对默认项目模板的标记和CSS做了改进，这样最新创建的项目放在移动设备上可以和桌面上一样好看。例如，我们添加了viewport元标记，页面在小屏幕上也可以布局得很好，即便页面专为桌面设计，也不会出现奇怪的放大和缩小。下图比较了使用新旧模板构建的页面：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image006" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327243285.gif" alt="clip_image006" width="628" height="356" border="0" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;新的&amp;ldquo;Mobile Application&amp;rdquo;项目模板&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;另一个正在考虑的改变是专门用于移动和平板Web应用程序的项目模板。该项目模板会包含布局、视图和脚本（如jQuery Mobile），用于构建可提供富用户体验和为现代移动设备进行了优化的应用程序。用该模板构建的页面可能会如下所示：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image008" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327257580.gif" alt="clip_image008" width="240" height="244" border="0" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;针对特殊设备的视图&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;你常常需要剪裁用户界面以适应用户的设备。我们希望能使针对特殊设备类型的视图、分部视图和布局进行的重写（override）能变得简单。无论你是创建全新项目还是将已有项目升级到ASP.NET MVC 4，该特性都能正常工作。&lt;/p&gt;&lt;p&gt;例如，你可以针对移动设备重写一个特殊的视图，只需创建以&amp;ldquo;.Mobile&amp;rdquo;为文件名后缀的新视图即可：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image010" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327265595.gif" alt="clip_image010" width="436" height="330" border="0" /&gt;&lt;/p&gt;&lt;p&gt;我们还可能会提供一个新的基于jQuery Mobile的视图模板，并增强Add View和Add Controller对话框，这样你就可以为新的或已存在的controller和action快速添加基于jQuery Mobile的视图重写。下图展示了一个Add Controller对话框可能的外观：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image012" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327272955.gif" alt="clip_image012" width="535" height="486" border="0" /&gt;&lt;/p&gt;&lt;p&gt;View type列表中的选项与应用程序使用的视图引擎无关。视图转换时不会改变的那些选项被移到了View Options对话框中，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image014" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111241327287000.gif" alt="clip_image014" width="443" height="388" border="0" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;设备切换器&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;很多都网站都为访问者提供了一种简单的方式，可以从移动体验切换到桌面体验。我们考虑添加一个设备切换器，它既是呈现适当UI的辅助器（从移动切换到桌面或反之，取决于当前的设备设置），也是让用户决定使用哪种体验的API。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;支持Razor 辅助方法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;ASP.NET Web页面可以在Web应用程序目录的App_Code文件夹中添加.cshtml或.vbhtml文件，使用Razor语法来编写辅助方法。尽管在ASP.NET MVC项目中也可以添加这些文件，但它们不能访问ASP.NET MVC上下文对象（如ViewContext）或ASP.NET MVC HtmlHelper实例。&lt;/p&gt;&lt;p&gt;在ASP.NET MVC 4中，我们以一种MVC特定的方式支持了Razor辅助方法。我们还在研究在类库项目中编写Razor辅助方法的工具，这样就可以将它们编译成库了。我们可以在其他项目中复用这些库，并编写单元测试。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;AsyncController类支持Task和Task&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;用ASP.NET MVC的现有版本编写异步action是很困难的。例如，下面的ASP.NET MVC 3代码片段展示了一个action方法，它调用了两个不同的异步服务。&lt;/p&gt;&lt;span style="color: blue;"&gt;public void &lt;/span&gt;IndexAsync(&lt;span style="color: blue;"&gt;string &lt;/span&gt;city) &lt;br/&gt;{ &lt;br/&gt;    AsyncManager.OutstandingOperations.Increment(2); &lt;br/&gt;    NewsService newsService = &lt;span style="color: blue;"&gt;new &lt;/span&gt;NewsService(); &lt;br/&gt;    newsService.GetHeadlinesCompleted += (sender, e) =&amp;gt; &lt;br/&gt;    { &lt;br/&gt;        AsyncManager.Parameters[&lt;span style="color: #a31515;"&gt;"headlines"&lt;/span&gt;] = e.Value; &lt;br/&gt;        AsyncManager.OutstandingOperations.Decrement(); &lt;br/&gt;    }; &lt;br/&gt;    newsService.GetHeadlinesAsync(); &lt;br/&gt;    SportsService sportsService = &lt;span style="color: blue;"&gt;new &lt;/span&gt;SportsService(); &lt;br/&gt;    sportsService.GetScoresCompleted += (sender, e) =&amp;gt; &lt;br/&gt;    { &lt;br/&gt;        AsyncManager.Parameters[&lt;span style="color: #a31515;"&gt;"scores"&lt;/span&gt;] = e.Value; &lt;br/&gt;        AsyncManager.OutstandingOperations.Decrement(); &lt;br/&gt;    }; &lt;br/&gt;    sportsService.GetScoresAsync(); &lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color: blue;"&gt;public &lt;/span&gt;ActionResult IndexCompleted(&lt;span style="color: blue;"&gt;string&lt;/span&gt;[] headlines, &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] scores, &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] forecast)&lt;br/&gt;{ &lt;br/&gt;    &lt;span style="color: blue;"&gt;return &lt;/span&gt;View(&lt;span style="color: #a31515;"&gt;"Common"&lt;/span&gt;, &lt;span style="color: blue;"&gt;new &lt;/span&gt;PortalViewModel { &lt;br/&gt;        NewsHeadlines = headlines, &lt;br/&gt;        SportsScores = scores, &lt;br/&gt;    }); &lt;br/&gt;}&lt;p&gt;而使用ASP.NET MVC 4和&lt;a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=9983"&gt;Visual Studio Async CTP&lt;/a&gt;（或在未来使用&lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2010/10/28/asynchrony-in-c-5-part-one.aspx"&gt;支持await关键字&lt;/a&gt;的C# 5），异步的action方法就变为：&lt;/p&gt;&lt;span style="color: blue;"&gt;public &lt;/span&gt;async Task&amp;lt;ActionResult&amp;gt; Index(&lt;span style="color: blue;"&gt;string &lt;/span&gt;city) &lt;br/&gt;{    &lt;br/&gt;    var newsService = &lt;span style="color: blue;"&gt;new &lt;/span&gt;NewsService();    &lt;br/&gt;    var sportsService = &lt;span style="color: blue;"&gt;new &lt;/span&gt;SportsService();        &lt;br/&gt;    &lt;span style="color: blue;"&gt;return &lt;/span&gt;View(&lt;span style="color: #a31515;"&gt;"Common"&lt;/span&gt;,  &lt;span style="color: blue;"&gt;new &lt;/span&gt;PortalViewModel {        &lt;br/&gt;        NewsHeadlines = await newsService.GetHeadlinesAsync(),        &lt;br/&gt;        SportsScores = await sportsService.GetScoresAsync()    &lt;br/&gt;    });&lt;br/&gt;}&lt;p&gt;&lt;strong&gt;CSS和JavaScript打包集成&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;ASP.NET MVC 4将包含CSS和JavaScript打包程序，可以将多个.css和.js文件合并为一个文件，通过移除不必要的空白和注释，可以减少最终的文件尺寸。这降低了带宽使用和下载时间，提升了页面的呈现速度。&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;EF Code First Data Migrations，支持从一个数据库架构版本迁移到另一个，不会丢失数据。&lt;/li&gt;&lt;li&gt;对应用程序代码的功能和集成测试提供更好的支持。&lt;/li&gt;&lt;li&gt;支持WCF Web API。&lt;/li&gt;&lt;li&gt;全面地改善Ajax。我们希望减少开发者在ASP.NET MVC中使用Ajax时遇到的困难。&lt;/li&gt;&lt;li&gt;编辑器/显示模板和HTML辅助方法支持HTML5。例如，在呈现一个DateTime属性时，编辑器模板将呈现一个type设置为date的input元素，而不是type设置为默认的text的input元素。此外，现有的HTML辅助方法如TextBoxFor也将得到更新，可以根据模型类型呈现适当的input元素。&lt;/li&gt;&lt;li&gt;移动Web项目的模板。&lt;/li&gt;&lt;li&gt;支持Razor视图中的&amp;ldquo;&lt;a name="OLE_LINK2"&gt;&lt;/a&gt;&lt;a name="OLE_LINK1"&gt;&lt;/a&gt;donut hole&amp;rdquo;缓存和Windows Server App Fabric缓存提供程序。&lt;/li&gt;&lt;li&gt;新的AreaAttribute类，在使用area时提供更好的安全性。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;免责声明&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;本文档只是一个初步的文档，因此本节在软件最终发布之前可能会有重大修改。&lt;/p&gt;&lt;p&gt;本文档中的内容代表了微软自文档发布之日起对当前问题的看法。由于微软需要及时响应不断变化的市场，因此不能将本文档看成是一种承诺，微软也无法保证任何信息的准确性。&lt;/p&gt;&lt;p&gt;这篇White Paper仅供参考。对于文档中出现的信息，微软不做任何法律上的担保、明示、暗示。&lt;/p&gt;&lt;p&gt;遵守所有适用的版权法是用户的责任。在不限制版权法所规定的权利的前提下，如果没有微软的书面许可，不能以任何形式任何方式（电子、机械、复印、录音或其他）任何目的，对本文档的任何内容进行复制、存储、引入索引或传输。&lt;/p&gt;&lt;p&gt;微软享有此文档中的专利、专利申请、商标、版权或其他知识产权。除非微软的书面许可中有明确的规定，否则不能使用该文档中的任何专利、商标、版权和其他知识产权。&lt;/p&gt;&lt;p&gt;如果没有额外说明，这里的公司、组织、产品、域名、e-mail、logo、人、地点、事件等均为虚构，没有暗示也不能据此推断任何有关的实际的公司、组织、产品、域名、e-mail、logo、人、地点和事件。&lt;/p&gt;&lt;p&gt;&amp;copy; 2011 Microsoft Corporation.&amp;nbsp; All rights reserved.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2261540.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/11/24/asp-net-mvc-4-roadmap.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/11/15/2249915.html</id><title type="text">解决安装Visual Studio 2010 SP1时被NDP40-KB2468871.exe补丁卡死以及mscorsvw.exe进程CPU占用率高的问题</title><summary type="text">前两天换了块硬盘重新做了系统，昨天在安装Visual Studio 2010 SP1的时候，被卡死在最后一步安装NDP40-KB2468871.exe补丁的这个阶段，大概有两个多小时，最后无耐只好回滚。</summary><published>2011-11-15T08:45:00Z</published><updated>2011-11-15T08:45:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/11/15/2249915.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/11/15/2249915.html"/><content type="html">&lt;p&gt;前两天换了块硬盘重新做了系统，昨天在安装Visual Studio 2010 SP1的时候，被卡死在最后一步安装NDP40-KB2468871.exe补丁的这个阶段，大概有两个多小时，最后无耐只好回滚。Google了一下，看来&lt;a href="http://www.google.com.hk/search?hl=zh-CN&amp;amp;source=hp&amp;amp;biw=&amp;amp;bih=&amp;amp;q=NDP40-KB2468871.exe&amp;amp;btnG=Google+%E6%90%9C%E7%B4%A2"&gt;有这种情况的还真不少&lt;/a&gt;，尤其是这篇&lt;a href="http://blogs.msdn.com/b/heaths/archive/2011/03/02/visual-studio-2010-service-pack-1-installing-for-over-2-hours-could-be-a-sign-of-a-problem.aspx"&gt;Visual Studio 2010 Service Pack 1 installing for over 2 hours could be a sign of a problem&lt;/a&gt;，跟我的问题如出一辙。但其中介绍的方法仍然不能解决问题。&lt;/p&gt;&lt;p&gt;与此同时还有另一个问题，就是mscorsvw.exe这个进程始终占用50%左右的CPU使用率，杀不掉，就算杀了，过几秒钟又自动起来了。关Microsoft .NET Framework NGEN服务也不行，而且这个服务似乎根本就没法禁用。以前的系统也有这个现象，所以我写了一个工具，自动查杀这个进程，这下又派上了用场。&lt;/p&gt;&lt;p&gt;不能完整安装SP1始终是不爽的，最后抱着试一试的想法&lt;a href="http://weibo.com/1405716845/xxxGxyfAN"&gt;求助于微博&lt;/a&gt;，没想到&lt;a href="http://weibo.com/1688446613/xxyMIzuww"&gt;Ivony大神一语惊醒梦中人&lt;/a&gt;，是360！于是重启，关闭360，杀mscorsvw.exe进程，重新运行SP1，到NDP40-KB2468871.exe时又尼玛卡住了。不过这次我意识到是不是mscorsvw.exe的问题，于是关闭了杀进程的工具，等mscorsvw.exe自动开启，这时安装瞬间就完成了。&lt;/p&gt;&lt;p&gt;重启之后再看任务管理器，mscorsvw.exe进程安安静静地躺在那里，不悲不喜。&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/kirinboy/201111/201111151645275933.png" alt="image" width="338" height="45" border="0" /&gt;&lt;/p&gt;&lt;p&gt;这之后我又用&lt;a href="http://www.microsoft.com/web/downloads/platform.aspx"&gt;Web Platform Installer&lt;/a&gt;安装其他组件，但仍然出现卡死的现象，毙掉360，安装成功。&lt;/p&gt;&lt;p&gt;总之一句话&lt;/p&gt;&lt;p&gt;&lt;strong&gt;深爱生命，远离360！&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2249915.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/11/15/2249915.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kirinboy/archive/2011/11/14/csharp-book-list-from-eric-lippert.html</id><title type="text">Eric Lippert推荐的C#书单</title><summary type="text">Eric Lippert是微软C#编译器和C#语言设计小组的重要成员，他还经常出没于Stack Overflow社区，解答开发者提出的问题。其中被问到最多的问题是：能否推荐一些学习C#的好书。最近，在接受InformIT采访时也被问到了这个问题，于是Eric列出了一份C#书单。</summary><published>2011-11-14T05:48:00Z</published><updated>2011-11-14T05:48:00Z</updated><author><name>麒麟.NET</name><uri>http://www.cnblogs.com/kirinboy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kirinboy/archive/2011/11/14/csharp-book-list-from-eric-lippert.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kirinboy/archive/2011/11/14/csharp-book-list-from-eric-lippert.html"/><content type="html">&lt;p&gt;&lt;a href="http://blogs.msdn.com/b/ericlippert/"&gt;Eric Lippert&lt;/a&gt;是微软C#编译器和C#语言设计小组的重要成员，他还经常出没于&lt;a href="http://stackoverflow.com/questions/tagged/c%23"&gt;Stack Overflow社区&lt;/a&gt;，解答开发者提出的问题。其中被问到最多的问题是：能否推荐一些学习C#的好书。最近，在接受&lt;a href="http://www.informit.com"&gt;InformIT&lt;/a&gt;采访时也被问到了这个问题，于是Eric列出了&lt;a href="http://www.informit.com/articles/article.aspx?p=1769249"&gt;一份C#书单&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780672331015"&gt;&lt;strong&gt;Sams Teach Yourself Visual C# 2010 in 24 Hours&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; by Scott Dorman&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: left;" src="http://www.informit.com/ShowCover.aspx?isbn=0672331012&amp;amp;type=f" alt="Sams Teach Yourself Visual C# 2010 in 24 Hours: Complete Starter Kit" width="80" height="104" align="left" /&gt;&lt;/p&gt;&lt;p&gt;Eric声称，他并没有被这个名字吓到，倒是被它的内容吓到了。它的价格对于C#初学者来说是相当实惠的（注：该实惠价为$34.99，请对比国内的技术书籍价格）。此外，Scott并没有像其他入门书作者那样，用作者的学习路线来组织本书的结构，相反，而是循序渐进、由浅入深地。&lt;/p&gt;&lt;p&gt;这本书国内没有引进，而且估计没有出版社敢引进。就这个《24小时学会Visual C# 2010》的书名就吓退了所有出版社。别说24小时，就是《24天学会XXX》也会被喷死。这不能怪读者，这是被那些早期的垃圾作者们逼的。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780321694690"&gt;&lt;strong&gt;Essential C# 4.0&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; by Mark Michaelis &lt;br /&gt;&lt;/strong&gt;&lt;a href="http://my.safaribooksonline.com/book/programming/csharp/9781935182474"&gt;&lt;strong&gt;C# In Depth, 2nd Edition&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; by Jon Skeet&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: right;" src="http://www.informit.com/ShowCover.aspx?isbn=0321694694&amp;amp;type=f" alt="Essential C# 4.0, 3rd Edition" width="80" height="104" align="right" /&gt;&lt;/p&gt;&lt;p&gt;这两本书Eric经常推荐给中高级C#程序员，这两本书都将全部注意力放到了C#语言上，只是偶尔提到了.NET基础框架。&lt;a href="http://www.informit.com/authors/bio.aspx?a=cae5dd08-0dc1-434e-8a46-16e8927c2fc5"&gt;Mark Michaelis&lt;/a&gt;的书不仅适合初学者，也适合C#熟手，以及从其他语言转型过来的程序员。（&lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2010/04/15/it-s-essential.aspx"&gt;Eric在以前的博文中就曾经推荐过这本书&lt;/a&gt;。）&lt;a href="http://www.ituring.com.cn"&gt;图灵&lt;/a&gt;引进了这本书的中文版，叫做《&lt;a href="http://www.ituring.com.cn/book/129"&gt;C#本质论（第三版）&lt;/a&gt;》，由&lt;a href="http://transbot.blog.163.com/"&gt;周靖老师&lt;/a&gt;翻译。我翻开这本书的时候就感到十分亲切，因为代码的字体用的是我最喜欢的Consolas，读起来畅快淋漓。每一章的开头都有一个思维导图来展示本节的内容，这比仅仅使用一个列表要生动得多，也更利于记忆。&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: left;" src="http://my.safaribooksonline.com/static/201111-6351-my/images/9781935182474/9781935182474_s.jpg" alt="C# in Depth, Second Edition" width="80" height="100" align="left" /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://msmvps.com/blogs/jon_skeet/Default.aspx"&gt;Jon Skeet&lt;/a&gt;是&lt;a href="http://stackoverflow.com/users/22656/jon-skeet"&gt;StackOverflow传奇&lt;/a&gt;，他的书从C# 1.0开始，介绍了各个C#版本的语言特性。如果说Essential C#传达了C#的本质，那么C# in Depth则深入了C#各个晦涩的角落。Jon的英式幽默还贯穿了整本书。&lt;/p&gt;&lt;p&gt;我本人有幸参与了&lt;a href="http://www.ituring.com.cn/book/763"&gt;该书第二版&lt;/a&gt;的翻译，不出意外年底就应该上市了。此书的价值堪比&lt;a href="http://book.douban.com/subject/4112979/"&gt;CLR via C#&lt;/a&gt;在CLR领域的地位。我过两天会专门撰文来推荐此书。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780321658708"&gt;Effective C#, 2nd Edition&lt;/a&gt; by Bill Wagner &lt;/strong&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780321485892"&gt;More Effective C#&lt;/a&gt; by Bill Wagner&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: left;" src="http://www.informit.com/ShowCover.aspx?isbn=0321485890&amp;amp;type=f" alt="More Effective C#: 50 Specific Ways to Improve Your C#" width="80" height="106" align="left" /&gt;&lt;img style="display: inline; float: left;" src="http://www.informit.com/ShowCover.aspx?isbn=0321658701&amp;amp;type=f" alt="Effective C#  (Covers C# 4.0): 50 Specific Ways to Improve Your C#, 2nd Edition" width="80" height="105" align="left" /&gt; 这两本书都不是初学者教程，而是分别探讨了50个编写高质量C#代码的技巧。&lt;a href="http://www.srtsolutions.com/author/billwagner"&gt;Bill Wagner&lt;/a&gt;总是能简明准确地解释复杂的主题。如果你想了解优秀的（或糟糕的）C#实践，可以浏览&lt;a href="http://msdn.microsoft.com/en-us/vcsharp/ee942788.aspx"&gt;Bill在MSDN Developer Center上的文章&lt;/a&gt;。这两本书和他的文章将指引优秀的程序员迈向通往伟大的道路。&lt;/p&gt;&lt;p&gt;图灵同样出版了了这&lt;a href="http://www.ituring.com.cn/book/92"&gt;两本书&lt;/a&gt;的&lt;a href="http://book.douban.com/subject/4101150/"&gt;中文版&lt;/a&gt;（以及&lt;a href="http://www.ituring.com.cn/book/585"&gt;Effective C#第一版&lt;/a&gt;），由MVP&lt;a href="http://weibo.com/dflyingchen"&gt;陈黎夫&lt;/a&gt;翻译（Effective C#第一版由&lt;a href="http://weibo.com/jzli"&gt;李建忠老师&lt;/a&gt;翻译）。这三本书的中译本，都属上乘之作，语言流畅，理解透彻，绝对的百里挑一。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780321741769"&gt;The C# Programming Language, 4th edition&lt;/a&gt;&lt;/strong&gt;&lt;strong&gt; by Anders Hejlsberg, Mads Torgersen, Scott Wiltamuth and Peter Golde&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: right;" src="http://www.informit.com/ShowCover.aspx?isbn=0321741765&amp;amp;type=f" alt="C# Programming Language (Covering C# 4.0), The, 4th Edition" width="80" height="104" align="right" /&gt;&lt;/p&gt;&lt;p&gt;这是C#之父Anders Hejlsberg一直在更新的书（每当C#出一个版本，就会更新一次），&lt;a href="http://book.douban.com/subject/4118574/"&gt;第三版的中译本&lt;/a&gt;由华章出版。我本人没有看过这本书，因为它几乎就是&lt;a href="http://msdn.microsoft.com/en-us/library/ms228593.aspx"&gt;C#语言规范&lt;/a&gt;的翻版，所以我选择打印一本语言规范放在桌旁，以备不时之需。但实际上按照Eric的说法，本书远不止此，还包括诸多C#专家（包括Eric本人、Jon Skeet、Bill Wagner等）的注释。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=9780321336781"&gt;Java Puzzlers&lt;/a&gt; by Joshua Bloch and Neal Gafter&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: right;" src="http://www.informit.com/ShowCover.aspx?isbn=032133678X&amp;amp;type=f" alt="Java&amp;trade; Puzzlers: Traps, Pitfalls, and Corner Cases" width="80" height="100" align="right" /&gt;你一定会奇怪为什么C#书单里会混杂着一本Java书籍，Eric的解释是：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;它很有趣&lt;/li&gt;&lt;li&gt;&lt;a href="http://gafter.blogspot.com/"&gt;Neal Gafter&lt;/a&gt; 和&lt;a href="http://research.google.com/pubs/author32.html"&gt;Joshua Bloch&lt;/a&gt;所指出的这些陷阱对语言的设计者来说是一个警醒。如果开发者落入了陷阱，这是语言设计者的责任，因为他们应该让程序员能轻松有效地避开这些陷阱。&lt;/li&gt;&lt;li&gt;本书介绍的一半以上的陷阱会在等价的C#程序中产生警告或错误！不管是语言设计还是生活，要避免犯错误，就要从其他人犯的错误中吸取教训。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Neal现在在微软C#设计和实现小组工作，也许有一天你会看到一本C# Puzzlers。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.ituring.com.cn/book/88"&gt;本书中译本《Java解惑》&lt;/a&gt;依然由图灵发行（你一定想问为什么图灵引进了这么多好书，去&lt;a href="http://www.ituring.com.cn"&gt;图灵社区&lt;/a&gt;逛逛吧）。我在前两天京东促销时刚刚入手，准备近期开看。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.amazon.com/Introduction-Algorithms-Thomas-H-Cormen/dp/0262033844"&gt;Introduction to Algorithms, 3rd Edition&lt;/a&gt; by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein &lt;/strong&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href="http://www.amazon.com/Purely-Functional-Structures-Chris-Okasaki/dp/0521663504/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1318533411&amp;amp;sr=1-1"&gt;Purely Functional Data Structures&lt;/a&gt; by Chris Okasaki&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: left;" src="http://ecx.images-amazon.com/images/I/41kXXE4mAKL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA300_SH20_OU01_.jpg" alt="Introduction to Algorithms" width="80" height="80" align="left" /&gt;&lt;/p&gt;&lt;p&gt;这两本书都不直接与C#有关，但Eric却经常向人们推荐。Introduction to Algorithms（著名的&lt;a href="http://book.douban.com/subject/1885170/"&gt;算法导论&lt;/a&gt;，华章出版）在微软几乎人手一本。很多计算机科学科班出身的开发者很少在日常开发中使用他们学到的理论原则，但C#编译器小组可不是这样。商业软件开发者如果精通计算机科学理论，也可以获益良多。&lt;/p&gt;&lt;p&gt;&lt;img style="display: inline; float: right;" src="http://ecx.images-amazon.com/images/I/41XlPaC%2BZqL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA300_SH20_OU01_.jpg" alt="Purely Functional Data Structures" width="80" height="80" align="right" /&gt;我们正处于函数式编程复兴的年代。像F#这样的函数式语言越来越受欢迎，并且纯函数式语言中的一些理念正在逐步融入主流面向对象语言。比如C#和VB中的LINQ，在很大程度上受到了Haskell式的单体查询的影响。同样，纯粹的函数式数据结构在并发程序中能工作地更好。大而全的算法书主要关心的是传统的数据结构，如可变数组、栈、队列等，而Chris Okasaki的这本薄而优雅的算法书则主要关注的是用不可变的、线程安全的、内存高效的部分构建复杂的数据结构。本书中的很多内容都可以&lt;a href="http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf"&gt;在线浏览&lt;/a&gt;。C#开发者可能不太适应其紧凑的语法，F#开发者可能要感觉好得多。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;以上就是Eric的C#书单，您看过几本呢？&lt;/p&gt;&lt;p&gt;您一定会问为什么没有CLR via C#？为什么没有&lt;a href="http://book.douban.com/subject/4304959/"&gt;C# 4.0 in a nutshell&lt;/a&gt;？Eric这里列出的是个C#书单，可能他觉得CLR via C#太偏重CLR了吧。而对于C# in a nutshell，Eric坦言他并没有读过这本书，所以就没有推荐了。&lt;/p&gt;&lt;p&gt;其实也没有必要问这么多为什么，您心里一定也有一个自己的C#书单，重要的是把这些书读了，并融汇贯通。但就我目前的了解来看，国内的语言书都卖得不好，图灵出版的C#本质论、深入解析C#以及Effective C#系列，都可以用惨淡来形容（好像没有一本能撑到第二次印刷，也就是说每本书只卖出去不到3000本）。园子里也经常有人要求推荐书，但为什么技术书市场还这么惨不忍睹呢？关键是，您得去买书啊，对不？&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kirinboy/aggbug/2248286.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kirinboy/archive/2011/11/14/csharp-book-list-from-eric-lippert.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
