<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>简单生活 -- Kevin Yang的博客 &#187; 其他随笔</title>
	<atom:link href="http://www.imkevinyang.com/categories/techarticles/othertecharticles/feed" rel="self" type="application/rss+xml" />
	<link>http://www.imkevinyang.com</link>
	<description>It&#039;s all about sharing</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:37:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>微软Azure平台的计费模型</title>
		<link>http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afazure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html</link>
		<comments>http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afazure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html#comments</comments>
		<pubDate>Fri, 12 Nov 2010 01:00:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[AppFabric]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[Sql Azure]]></category>
		<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[云存储]]></category>
		<category><![CDATA[云平台]]></category>
		<category><![CDATA[云计算]]></category>
		<category><![CDATA[微软]]></category>
		<category><![CDATA[计费]]></category>
		<category><![CDATA[费用]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afazure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html</guid>
		<description><![CDATA[<p>微软的Azure平台在今年也就是2010年开始投入商用，很多公司也在尝试着基于Azure平台开发或者移植自己的应用程序到云平台上。在这过程中，计费是大家非常关注的一个问题，毕竟涉及到钱的问题。微软官方Portal上面列出了Azure平台各类服务的收费标准，不过很杂乱，也有很多细节不清楚的地方，很多人&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>微软的Azure平台在今年也就是2010年开始投入商用，很多公司也在尝试着基于Azure平台开发或者移植自己的应用程序到云平台上。在这过程中，计费是大家非常关注的一个问题，毕竟涉及到钱的问题。微软官方Portal上面列出了Azure平台各类服务的收费标准，不过很杂乱，也有很多细节不清楚的地方，很多人看了之后还是会比较晕。在这里我会从另一个视角来介绍这些费用，希望对你有所帮助。</p>
<p>Azure平台的计费模型可以分为以下几个方面：</p>
<ul>
<li>计算费用</li>
<li>存储费用</li>
<li>请求事务费用</li>
<li>连接费用</li>
<li>带宽费用</li>
</ul>
<p>在开始介绍之前需要说明一下，下面我提到的"Azure平台"，是笼统的包括整个云平台提供的所有服务，而当我提到"Windows Azure"的时候，则不包括Sql Azure和AppFabric服务的。</p>
<h2><strong>计算费用</strong></h2>
<p>在Windows Azure中创建的Hosted Service就是一个计算服务（Compute Service）。每个计算服务提供了两个部署平台插槽，Production和Stage，Production平台通常用于生产环境，对外地址是固定的，在创建Service的时候就已经确定了。而Stage一般用于测试开发，地址随每次部署变更。</p>
<p>一般的开发流程是先将应用程序部署到Stage平台上，测试完毕之后将其切换到Production平台。</p>
<p><strong>但是Production和Stage平台的收费标准没有任何区别</strong>。</p>
<p>每个计算服务由若干个角色（Role）组成，每个角色由若干个计算实例（Compute Instance）组成。每个计算实例都运行在单独的VM中，我们可以把VM理解为一台单独的机器，它拥有独立的CPU数目，内存以及本地存储。VM有不同规格的配置，依次为Small,medium,large,extralarge，如下表所示。</p>
<p><img style="display: inline; border-width: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/11/image.png" border="0" alt="image" width="521" height="121" /></p>
<p>计算服务的计费公式：</p>
<p><span style="background-color: #fc6;"> </span></p>
<p>使用小时数 * 实例数（也就是VM的数目） * 计费基准（也就是0.12 x 不同规格VM使用的CPU数目）</p>
<p>或者这个公式可能更好理解： <span style="background-color: #fc6;">使用小时数 * 使用的CPU总数 * 0.12</span></p>
<p>这里需要注意两点：</p>
<p>1. 使用小时数是从一部署就开始计算，除非删除应用，否则一直算钱。不足一小时以一小时计算。</p>
<p>2. 实例数包括了Production和Stage两个平台。</p>
<h2><strong>存储费用</strong></h2>
<p>Azure平台的存储费用包括两个部分，一个是Windows Azure存储，另一个是Sql Azure数据库存储。</p>
<p><strong>Windows Azure提供的存储服务包括Table、Queue和Blob存储</strong>。以月作为一个周期，统计一个月内上传的容量，然后平摊到每一天得到平均值。根据这个日平均值来收费。</p>
<p><span style="background-color: #fc6;">Windows Azure存储费用为$0.15 /GB</span></p>
<p>而Sql Azure根据创建的数据库大小不同，收费也不同，和Windows Azure存储服务类似，也是统计每个月创建的数据库总容量，然后平摊到月内每一天，最后按照日平均值收费。</p>
<p><span style="background-color: #fc6;">Sql Azure数据库存储费用为$9.99 /GB</span></p>
<p>以11月份（30天）计费周期为例，你在1号的时候创建了一个10G的数据库，但是只用了15天，接下来的15天你已经删除这个数据库了，那么11月份的日均存储为(10*15+0*15) / 30 = 5G。和你创建一个5G的数据库然后用上整月的收费是一样的。 <strong> </strong></p>
<h2><strong>请求事务（Transaction）费用</strong></h2>
<p>向Azure平台服务发起的HTTP请求称为事务（Transaction）。包括以下几个方面：</p>
<ul>
<li>应用程序访问Windows Azure存储服务（Blob、Table、Queue）</li>
<li>CDN节点访问Windows Azure存储服务（Blob、Table、Queue）</li>
<li>应用程序向Access Control访问控制服务（AppFabric的一个组件）发起请求</li>
</ul>
<p>其中：</p>
<p>应用程序向Windows Azure存储服务发起的事务的费用为<span style="background-color: #fc6;">$0.01 /10K</span>，即1万次事务0.01美元；</p>
<p>CDN发起的事务为<span style="background-color: #fc6;">$0.01 /10K</span>；</p>
<p>应用程序向Access Control发起的事务为<span style="background-color: #fc6;">$1.99 /100K</span>，</p>
<h2>连接收费（Service Bus）</h2>
<p>Azure平台的AppFabric提供了两个服务，一个是Access Control访问权限控制，另外一个就是Service Bus。Service Bus允许你将企业内部的应用通过Azure平台发布到互联网上，以便和第三方应用程序通讯。注意，应用程序本身并没有部署到Azure平台，Service Bus只是起一个数据转接的作用。下面是一个简单的示意流程：</p>
<p><strong>企业应用=&gt;企业防火墙=&gt;AppFabric Service Bus服务=&gt;暴露通讯端点</strong></p>
<p>第三方应用程序就通过Azure平台上Service Bus暴露的互联网唯一通讯地址来和企业应用进行通讯。</p>
<p>这个过程会产生一些网络连接，包括第三方应用程序和Service Bus端点之间的连接，以及Service Bus和企业应用程序之间的连接。</p>
<p><strong>Azure会按照一个月内平均的每天最大并发连接数目来进行计费</strong>。</p>
<p>那么这个每天最大并发连接数怎么计算出来的呢？</p>
<p>Azure每天以5分钟为间隔，统计当前<strong>时刻</strong>的并发连接数，这样一天下来就可以得到当天的最大并发连接数了。将一个月内每天的最大并发连接数累加起来，再平摊到每一天上就得到当前计费周期的日平均最大并发连接数，按此数值收费。</p>
<p>你可以选择按需计费，也可以选择购买固定最大连接数。这两种资费标准不同。</p>
<p><span style="background-color: #fc6;">按需计费，每个连接为$3.99，而购买固定连接数，每个连接只需花费$1.99</span>。Azure提供了5, 25, 100 或者500个连接的这几种套餐。</p>
<p>如果你的网站并发数不确定，那么你可以选择按需支付，这样每天的并发连接数再大也不会有问题（尽管如此，Azure自身还是限制了最大的并发数），只不过你需要多付一些钱而已。但对于那些能够预先估计自己的日最大并发连接数的客户来说，他可以选择购买固定连接数套餐，这样一个月的花费就是确定的了。当然，这样的坏处就是，一旦超过购买的峰值连接数，就无法接受新的连接。</p>
<p>例如某个小型网站，预计每天最大并发数不超过20个连接，那么他可以购买25个连接的套餐，这样一个月就固定花费49.75美元。</p>
<h2><strong>带宽费用</strong></h2>
<p><strong>一旦数据中心节点内外之间发生任何数据传输，均需要计入带宽费用</strong>。包括上面提到的存储请求、事务请求以及与AppFabric服务之间产生的数据交互，都需要计入带宽费用范畴。但是，<strong>同一个数据中心内的数据传输不收费</strong>。这也是为什么微软建议你尽量把应用都部署在同一个数据中心里头的缘故。</p>
<p>微软的数据中心可以分为主节点和CDN节点，这两种节点的带宽收费标准是不同的。</p>
<p>主节点的计费标准为：</p>
<p><span style="background-color: #fc6;">亚洲数据中心 $0.30 in / $0.45 out 每GB </span></p>
<p><span style="background-color: #fc6;">北美欧洲地区 $0.10 in / $0.15 out 每GB</span></p>
<p>需要注意的是，当用户第一次从CDN节点读取资源的时候，这个时候由于资源尚未缓存到该CDN节点，因此CDN节点需要从主节点获取该资源，这个数据传输也会按照上面的主节点带宽费用标准来计算。</p>
<p>CDN节点只会供用户下载资源，因此没有上行带宽费用。计费标准：</p>
<p><span style="background-color: #fc6;">北美以及欧洲地区费用 $0.15 每GB</span></p>
<p><span style="background-color: #fc6;">其他地区 $0.20 每GB</span></p>
<p>以上是我研究Azure计费模型的结果，写得不对的地方还请你指出。当然，这里头涉及到的具体计费标准未来肯定有所变动，但是基本的计费模型个人感觉应该已经比较完善了。更细节的计费问题以及最新的计费标准，请参考<a title="Windows Azure Platform Consumption" href="http://www.microsoft.com/windowsazure/offers/popup/popup.aspx?lang=en&amp;locale=en-US&amp;offer=MS-AZR-0003P" target="_blank">Windows Azure Platform Consumption</a>以及<a title="Windows Azure Pricing" href="http://www.microsoft.com/windowsazure/pricing/" target="_blank">Windows Azure Pricing</a>。</p>
<p style="text-align: right;">——<a title="微软Azure平台的计费模型" href="http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afAzure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/appfabric" title="AppFabric" rel="tag">AppFabric</a>, <a href="http://www.imkevinyang.com/tags/cdn" title="CDN" rel="tag">CDN</a>, <a href="http://www.imkevinyang.com/tags/sql-azure" title="Sql Azure" rel="tag">Sql Azure</a>, <a href="http://www.imkevinyang.com/tags/windows-azure" title="Windows Azure" rel="tag">Windows Azure</a>, <a href="http://www.imkevinyang.com/tags/%e4%ba%91%e5%ad%98%e5%82%a8" title="云存储" rel="tag">云存储</a>, <a href="http://www.imkevinyang.com/tags/%e4%ba%91%e5%b9%b3%e5%8f%b0" title="云平台" rel="tag">云平台</a>, <a href="http://www.imkevinyang.com/tags/%e4%ba%91%e8%ae%a1%e7%ae%97" title="云计算" rel="tag">云计算</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/microsoft" title="微软" rel="tag">微软</a>, <a href="http://www.imkevinyang.com/tags/%e8%ae%a1%e8%b4%b9" title="计费" rel="tag">计费</a>, <a href="http://www.imkevinyang.com/tags/%e8%b4%b9%e7%94%a8" title="费用" rel="tag">费用</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/05/google%e5%92%8c%e5%be%ae%e8%bd%af%e7%9a%84%e4%b8%80%e5%a4%a7%e4%b8%8d%e5%90%8c.html" title="Google和微软的一大不同 (2009/05/06)">Google和微软的一大不同</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html" title="Win7/Vista高级用户必备的右键菜单Take back my Ownership! (2009/12/06)">Win7/Vista高级用户必备的右键菜单Take back my Ownership!</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/%e5%8d%81%e5%b9%b4mfc%e7%bb%8f%e5%8e%86%e8%ae%a4%e8%af%86%e7%9a%84microsoft%e6%8a%80%e6%9c%af.html" title="十年MFC经历认识的Microsoft技术 (2009/03/17)">十年MFC经历认识的Microsoft技术</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%be%ae%e8%bd%af%e6%8a%80%e6%9c%af%e7%a4%be%e5%8c%ba%e7%b2%be%e8%8b%b1%e8%ae%a1%e5%88%92%e4%bd%a0%e4%b9%9f%e6%9d%a5%e5%8a%a0%e5%85%a5%e5%90%a7.html" title="微软技术社区精英计划&mdash;&mdash;你也来加入吧 (2010/06/02)">微软技术社区精英计划&mdash;&mdash;你也来加入吧</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afazure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Java/Js如何使用正则表达式匹配嵌套Html标签</title>
		<link>http://www.imkevinyang.com/2010/07/javajs%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html</link>
		<comments>http://www.imkevinyang.com/2010/07/javajs%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html#comments</comments>
		<pubDate>Fri, 30 Jul 2010 08:02:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[Html嵌套标签匹配]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[正则表达式]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/07/javajs%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html</guid>
		<description><![CDATA[<p>以前写过一篇文章讲解如何使用正则表达式完美解决Html嵌套标签的匹配问题（<a title="使用正则表达式匹配嵌套Html标签" href="http://www.imkevinyang.com/2009/07/%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D%E5%B5%8C%E5%A5%97html%E6%A0%87%E7%AD%BE.html" target="_blank">使用正则表达式匹配嵌套Html标签</a>），但是里头用到了平衡组这样的高级特性，貌似只有DotNet还有Perl正则引擎支持，因此通用性不高。有朋友留言说Java直接使用的话会报错。我后来查了一下，发现Java正则引擎支持的特性相对&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>以前写过一篇文章讲解如何使用正则表达式完美解决Html嵌套标签的匹配问题（<a title="使用正则表达式匹配嵌套Html标签" href="http://www.imkevinyang.com/2009/07/%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D%E5%B5%8C%E5%A5%97html%E6%A0%87%E7%AD%BE.html" target="_blank">使用正则表达式匹配嵌套Html标签</a>），但是里头用到了平衡组这样的高级特性，貌似只有DotNet还有Perl正则引擎支持，因此通用性不高。有朋友留言说Java直接使用的话会报错。我后来查了一下，发现Java正则引擎支持的特性相对比较少。在1.6版本中不能使用命名组（貌似1.7的时候开始支持了），否则会报以下错误，更别说平衡组了。因此感觉要实现无限级的嵌套匹配不大现实。</p>
<blockquote><p>java.util.regex.PatternSyntaxException: Look-behind group does not have an obvious maximum length near index<span style="background-color: #ffffff;"> XX</span></p></blockquote>
<p>在网上搜了好久也没找到完美的解决方案。不过，我们可以实现有限级Html嵌套标签匹配。思路相对于无限级来说就简单了好多，不需要那么多高级的特性。</p>
<p>示例：</p>
<pre class="brush: html">&lt;div id='container'&gt;
    &lt;div style='background-color:gray;' id='footer'&gt;
        &lt;a id='gotop' href='#' onclick='MGJS.goTop();return false;'&gt;Top&lt;/a&gt;
        &lt;a id='powered' href='http://wordpress.org/'&gt;WordPress&lt;/a&gt;
        &lt;div id='copyright'&gt;
            Copyright &amp;copy; 2009 简单生活 —— Kevin Yang的博客
         &lt;/div&gt;
        &lt;div id='themeinfo'&gt;
            Theme by &lt;a href='http://www.neoease.com/'&gt;mg12&lt;/a&gt;. Valid &lt;a href='http://validator.w3.org/check?uri=referer'&gt;XHTML 1.1&lt;/a&gt;
            and &lt;a href='http://jigsaw.w3.org/css-validator/'&gt;CSS 3&lt;/a&gt;.
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>在上面这个示例中，我们打算匹配id为footer的这个嵌套div，而且<strong>假设我们预先知道footer这个div里面最多只会嵌套一级div</strong>。更多级的情况我们一会儿再讲。</p>
<p>footer的开始和结束标签匹配很简单：</p>
<blockquote><p>&lt;div [^&gt;]*id='footer'[^&gt;]*&gt;......(这里的省略号是一会要填写的)&lt;/div&gt;</p></blockquote>
<p>夹在开始和结束标签之间的内容无非有两种情况：</p>
<ul>
<li>内容A: div标签，并且此div内无嵌套div</li>
<li>内容B: 任意其他内容</li>
</ul>
<p>然后就是这两种内容的不断重复而已。正则表示如下：</p>
<blockquote><p>(<span style="color: #ff0000;">&lt;div[^&gt;]*&gt;.*?&lt;/div&gt;</span>|<span style="color: #008000;"><strong>.</strong></span>)*?</p></blockquote>
<p>注意最后面的问号必须要加上，否则由于正则的贪婪匹配特性，footer的闭合标签会匹配失误。</p>
<p>OK了，<strong>匹配最多嵌套一级div</strong>的正则表达式如下：</p>
<blockquote><p>&lt;div [^&gt;]*id='footer'[^&gt;]*&gt;(<span style="color: #ff0000;">&lt;div[^&gt;]*&gt;.*?&lt;/div&gt;</span>|.)*?&lt;/div&gt;</p></blockquote>
<p>那么如果footer标签里头最多会嵌套两级div的话怎么办呢？</p>
<p>其实也不难，我们只需要把上面的“内容A”部分中的点号稍作替换即可。修改如下：</p>
<blockquote><p>&lt;div [^&gt;]*id='footer'[^&gt;]*&gt;(<span style="color: #ff0000;">&lt;div[^&gt;]*&gt;</span><span style="color: #0000ff;">(&lt;div[^&gt;]*&gt;.*?&lt;/div&gt;|.)</span>*?&lt;/div&gt;|.)*?&lt;/div&gt;</p></blockquote>
<p>到这里你可能就知道，如果要匹配最多嵌套三级div的话，正则应该怎么写了：</p>
<blockquote><p>&lt;div [^&gt;]*id='footer'[^&gt;]*&gt;(<span style="color: #ff0000;">&lt;div[^&gt;]*&gt;</span><span style="color: #0000ff;">(&lt;div[^&gt;]*&gt;</span><span style="color: #ff8000;">(&lt;div[^&gt;]*&gt;.*?&lt;/div&gt;|.)</span>*?&lt;/div&gt;|.)*?&lt;/div&gt;|.)*?&lt;/div&gt;</p></blockquote>
<p>所以实际上，只要你的html结构不是特别复杂的话，也就是说嵌套不会很深的话，那么你完全可以使用这种方式来匹配嵌套html标签。</p>
<p>这个正则在Java和Javascript中都可以使用，因为它没有用到任何高级特性。</p>
<p style="text-align: right;">——<a title="Java/Js如何使用正则表达式匹配嵌套Html标签" href="http://www.imkevinyang.com/2010/07/javajs%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D%E5%B5%8C%E5%A5%97html%E6%A0%87%E7%AD%BE.html" target="_self"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/html%e5%b5%8c%e5%a5%97%e6%a0%87%e7%ad%be%e5%8c%b9%e9%85%8d" title="Html嵌套标签匹配" rel="tag">Html嵌套标签匹配</a>, <a href="http://www.imkevinyang.com/tags/java" title="Java" rel="tag">Java</a>, <a href="http://www.imkevinyang.com/tags/javascript" title="Javascript" rel="tag">Javascript</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f" title="正则表达式" rel="tag">正则表达式</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/button%e6%a0%87%e7%ad%be%e9%bc%a0%e6%a0%87%e7%82%b9%e5%87%bb%e4%ba%8b%e4%bb%b6%e7%9a%84%e8%a7%a6%e5%8f%91%e6%ba%90%e9%97%ae%e9%a2%98.html" title="Button标签鼠标点击事件的触发源问题 (2009/11/27)">Button标签鼠标点击事件的触发源问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/ie%e4%b8%ad%e4%bd%bf%e7%94%a8windowopen%e6%89%93%e5%bc%80%e6%96%b0%e7%aa%97%e5%8f%a3%e6%97%b6%e6%97%a0%e6%b3%95%e8%8e%b7%e5%8f%96referrer%e5%af%b9%e8%b1%a1.html" title="IE中使用window.open打开新窗口时无法获取Referrer对象 (2009/03/07)">IE中使用window.open打开新窗口时无法获取Referrer对象</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/07/javascript-%e4%b8%ad%e7%9a%84false%e9%9b%b6%e5%80%bcnullundefined%e5%92%8c%e7%a9%ba%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%af%b9%e8%b1%a1.html" title="Javascript 中的false,零值,null,undefined和空字符串对象 (2009/07/07)">Javascript 中的false,零值,null,undefined和空字符串对象</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/javascript%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%87%ba%e9%94%99%e4%bb%a3%e7%a0%81%e6%89%80%e5%9c%a8%e6%96%87%e4%bb%b6%e5%8f%8a%e8%a1%8c%e6%95%b0.html" title="Javascript中获取出错代码所在文件及行数 (2009/05/18)">Javascript中获取出错代码所在文件及行数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/javascript%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%93%88%e5%b8%8c%e5%87%bd%e6%95%b0.html" title="Javascript字符串哈希函数 (2009/04/11)">Javascript字符串哈希函数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/06/javascript%e6%93%8d%e7%ba%b5cookie.html" title="Javascript操纵Cookie (2009/06/11)">Javascript操纵Cookie</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/%e4%b8%ba%e4%bb%80%e4%b9%88iis77-5%e7%9a%84gzip%e4%b8%8d%e8%b5%b7%e4%bd%9c%e7%94%a8.html" title="为什么IIS7/7.5的Gzip不起作用 (2010/05/08)">为什么IIS7/7.5的Gzip不起作用</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/07/%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html" title="使用正则表达式匹配嵌套Html标签 (2009/07/22)">使用正则表达式匹配嵌套Html标签</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e6%89%be%e5%87%ba%e4%b8%8d%e5%8c%85%e5%90%ab%e7%89%b9%e5%ae%9a%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%9a%84%e6%9d%a1%e7%9b%ae.html" title="使用正则表达式找出不包含特定字符串的条目 (2009/08/04)">使用正则表达式找出不包含特定字符串的条目</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e4%bd%bf%e7%94%a8%e7%9b%b8%e5%af%b9url%e6%97%a0%e7%bc%9d%e5%88%87%e6%8d%a2http-https.html" title="使用相对Url无缝切换HTTP-HTTPS (2009/09/18)">使用相对Url无缝切换HTTP-HTTPS</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/07/javajs%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Hilo: Windows 7下C++应用程序开发实战演练</title>
		<link>http://www.imkevinyang.com/2010/07/hilo-windows-7%e4%b8%8bc%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%bc%80%e5%8f%91%e5%ae%9e%e6%88%98%e6%bc%94%e7%bb%83.html</link>
		<comments>http://www.imkevinyang.com/2010/07/hilo-windows-7%e4%b8%8bc%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%bc%80%e5%8f%91%e5%ae%9e%e6%88%98%e6%bc%94%e7%bb%83.html#comments</comments>
		<pubDate>Tue, 20 Jul 2010 17:58:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Hilo]]></category>
		<category><![CDATA[Windows 7]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/07/hilo-windows-7%e4%b8%8bc%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%bc%80%e5%8f%91%e5%ae%9e%e6%88%98%e6%bc%94%e7%bb%83.html</guid>
		<description><![CDATA[<div class="statement">
<p> 英文原文链接：<a title="Hilo: Windows 7 C++ Development Walkthroughs" href="http://msdn.microsoft.com/en-us/windows/ff686707.aspx" target="_blank">Hilo: Windows 7 C++ Development Walkthroughs</a></p></div>
<p>&#34;Hilo&#34;由一系列文章以及示例代码组成的，它向你展示了如何释放Windows 7、Visual Studio 2010还有Visual C++的强大力量，来构建高性能，高响应的富客户端程序。Hi&#8230;</p>]]></description>
			<content:encoded><![CDATA[<div class="statement">
<p> 英文原文链接：<a title="Hilo: Windows 7 C++ Development Walkthroughs" href="http://msdn.microsoft.com/en-us/windows/ff686707.aspx" target="_blank">Hilo: Windows 7 C++ Development Walkthroughs</a></div>
<p>&quot;Hilo&quot;由一系列文章以及示例代码组成的，它向你展示了如何释放Windows 7、Visual Studio 2010还有Visual C++的强大力量，来构建高性能，高响应的富客户端程序。Hilo提供了源代码以及编写指导，帮助你设计和开发令人瞩目的触摸式Windows应用程序。</p>
<p>在接下来的几周时间里，我们将会在MSDN上发布一系列文章，讲述如何设计和实现一个可以浏览、检索和处理图像照片的触摸式Windows应用程序。这些文章将会涵盖Windows 7的核心技术，描述了如何将这些技术融合到一起来创建一个非常棒的用户体验，并且也会对应用程序的设计和实现等细节做详细的阐述。你可以在这个<a href="http://msdn.microsoft.com/library/ff708696.aspx" target="_blank">这里</a>找到此系列的第一篇文章。它对 Hilo做了一个概述性的介绍，并且说明了此系列中的这些文章和示例程序的所要达到的目标。</p>
<p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/07/clip_image001.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/clip_image001_thumb.jpg" width="244" height="181" /></a></p>
<p>我们接下来会逐步放出Hilo的相关源代码。第一次Hilo的发布包含了一个Hilo浏览器程序的源代码。这个程序实现了一种创新的旋转木马式的导航界面。这是触摸式的，你可以使用触摸手势快速的浏览和检索。你可以在<a href="http://code.msdn.microsoft.com/Hilo">这里</a>下载到此程序的源代码。</p>
<p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/07/clip_image002.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/clip_image002_thumb.jpg" width="244" height="176" /></a></p>
<p>Hilo文章系列，包括与此相关的源代码，是用来让你快速上手一些技术的开发，并且向你展示了如何在自己的应用程序中利用到Windows核心技术的优势。</p>
<p>如何开始</p>
<p>1. 为了编译和运行Hilo浏览器程序，你需要安装Visual Studio 2010以及Visual C++。你可以在这里下载到免费的Visual C++ 2010 Express版本。</p>
<p>2. 安装完Visual C++ 2010 Express之后，解压缩Hilo浏览器程序的源代码，双击打开Hilo.sln解决方案文件。</p>
<p>3. 在编译菜单中选择重新编译整个Hilo浏览器程序。</p>
<p>4. 按F5在调试模式下运行此程序。</p>

	标签：<a href="http://www.imkevinyang.com/tags/c" title="C++" rel="tag">C++</a>, <a href="http://www.imkevinyang.com/tags/hilo" title="Hilo" rel="tag">Hilo</a>, <a href="http://www.imkevinyang.com/tags/windows-7" title="Windows 7" rel="tag">Windows 7</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%80%e5%8f%91" title="开发" rel="tag">开发</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/02/c%e6%89%ab%e7%9b%b2%e7%b3%bb%e5%88%97%e4%b9%8b-%e6%8c%87%e9%92%88%e4%b8%93%e9%a2%98.html" title="c++扫盲系列之&#8211;指针专题 (2009/02/28)">c++扫盲系列之&#8211;指针专题</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/03/g1%e6%89%8b%e6%9c%ba%e4%b8%8e%e7%ac%94%e8%ae%b0%e6%9c%ac%e5%ae%9e%e7%8e%b0wifi%e4%ba%92%e8%81%94%e5%85%b1%e4%ba%ab%e4%b8%8a%e7%bd%91.html" title="G1手机与笔记本实现Wifi互联共享上网 (2010/03/02)">G1手机与笔记本实现Wifi互联共享上网</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/07/hilo-windows-7%e4%b8%8bc%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%bc%80%e5%8f%91%e5%ae%9e%e6%88%98%e6%bc%94%e7%bb%83.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sql Tips——Update语句也使用表别名(Table Alias)</title>
		<link>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html</link>
		<comments>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html#comments</comments>
		<pubDate>Thu, 01 Jul 2010 16:11:21 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Update]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[表别名]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html</guid>
		<description><![CDATA[<p>在编写Sql脚本时通过表别名可以大大缩减Sql代码，同时表别名也是解决同表多次引用的手段之一。在select中使用表别名大家应该都很熟悉了：</p>
<pre class="brush: sql">select * from TableA as A inner join TableB as B on A.Key1 = B.Key1</pre>
<p>但是在Update中使用表别名可能就没那么多人知道了。&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>在编写Sql脚本时通过表别名可以大大缩减Sql代码，同时表别名也是解决同表多次引用的手段之一。在select中使用表别名大家应该都很熟悉了：</p>
<pre class="brush: sql">select * from TableA as A inner join TableB as B on A.Key1 = B.Key1</pre>
<p>但是在Update中使用表别名可能就没那么多人知道了。</p>
<pre class="brush: sql">update T
set T.Key1 = 'xxxx'
from TableA T</pre>
<p>这些天在写Sql Update脚本的时候需要引用两次同个表对象，如果直接像下面这样引用两次TableA则会抛出“The multi-part identifier ‘TableA.Index’ could not be bound”的错误。这是因为Sql引擎无法知道你在where子句中的TableA到底指的是要Update的表还是from后面的表。</p>
<pre class="brush: sql">update TableA
set TableA.NextKey = T.Key
from TableA T
where T.Index = TableA.Index + 1</pre>
<p>如果不对Update后面的TableA使用别名的话，我们只能通过以下方法来实现。</p>
<pre class="brush: sql">update TableA
set TableA.NextKey = T.Key
from
(
  select * from TableA
)T
where T.Index = TableA.Index + 1</pre>
<p>使用别名可以得到更简洁的写法:</p>
<pre class="brush: sql">update T1
set T1.NextKey = T2.Key
from TableA T1, TableA T2
whereT2.Index = T1.Index + 1</pre>
<p style="text-align: right;">——<a title="Sql Tips——Update语句也使用表别名(Table Alias)" href="http://www.imkevinyang.com/2010/07/sql-tipsupdate%E8%AF%AD%E5%8F%A5%E4%B9%9F%E4%BD%BF%E7%94%A8%E8%A1%A8%E5%88%AB%E5%90%8Dtable-alias.html" target="_self"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/sql" title="SQL" rel="tag">SQL</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/update" title="Update" rel="tag">Update</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e6%95%b0%e6%8d%ae%e5%ba%93" title="数据库" rel="tag">数据库</a>, <a href="http://www.imkevinyang.com/tags/%e8%a1%a8%e5%88%ab%e5%90%8d" title="表别名" rel="tag">表别名</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> </li>
	<li><a href="http://www.imkevinyang.com/2011/06/onenote-tips-%e6%b7%b7%e5%90%88%e4%bd%bf%e7%94%a8%e4%b8%ad%e8%8b%b1%e6%96%87%e5%ad%97%e4%bd%93.html" title="OneNote Tips — 混合使用中英文字体 (2011/06/16)">OneNote Tips — 混合使用中英文字体</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/sql-server%e4%b8%ad%e4%bf%ae%e6%94%b9%e8%87%aa%e5%a2%9e%e9%95%bf%e5%88%97%e7%bb%8f%e5%b8%b8%e9%9c%80%e8%a6%81%e7%94%a8%e5%88%b0%e7%9a%84%e9%85%8d%e7%bd%ae.html" title="Sql Server中修改自增长列经常需要用到的配置 (2009/05/24)">Sql Server中修改自增长列经常需要用到的配置</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html" title="Sql Server重命名所有外键约束 (2010/08/02)">Sql Server重命名所有外键约束</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/ssis%e8%b0%83%e7%94%a8%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e5%a4%b1%e8%b4%a5.html" title="SSIS调用存储过程失败 (2010/05/23)">SSIS调用存储过程失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e9%87%8a%e6%94%besql-server%e5%8d%a0%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98.html" title="释放SQL Server占用的内存 (2009/09/01)">释放SQL Server占用的内存</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;）</title>
		<link>http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html</link>
		<comments>http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html#comments</comments>
		<pubDate>Fri, 18 Jun 2010 13:41:05 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[ASCII]]></category>
		<category><![CDATA[GB18030]]></category>
		<category><![CDATA[GB2312]]></category>
		<category><![CDATA[GBK]]></category>
		<category><![CDATA[OEM]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[UTF-16]]></category>
		<category><![CDATA[UTF-8]]></category>
		<category><![CDATA[字符]]></category>
		<category><![CDATA[字符编解码]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[编码]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html</guid>
		<description><![CDATA[<p>字符编码的问题看似很小，经常被技术人员忽视，但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识，希望对大家有所帮助。</p>
还是得从ASCII码说起
<p>说到字符编码，不得不说ASCII码的简史。计算机一开始发明的时候是用来解决数字计算的问题，后来人们发现，计算机还可以做更多的事，例如文本&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>字符编码的问题看似很小，经常被技术人员忽视，但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识，希望对大家有所帮助。</p>
<h2>还是得从ASCII码说起</h2>
<p>说到字符编码，不得不说ASCII码的简史。计算机一开始发明的时候是用来解决数字计算的问题，后来人们发现，计算机还可以做更多的事，例如文本处理。但由于计算机只识“数”，因此人们必须告诉计算机哪个数字来代表哪个特定字符，例如65代表字母‘A’，66代表字母‘B’，以此类推。但是<strong>计算机之间字符-数字的对应关系必须得一致，否则就会造成同一段数字在不同计算机上显示出来的字符不一样</strong>。因此美国国家标准协会ANSI制定了一个标准，规定了常用字符的集合以及每个字符对应的编号，这就是ASCII字符集（Character Set），也称ASCII码。</p>
<p>当时的计算机普遍使用8比特字节作为最小的存储和处理单元，加之当时用到的字符也很少，26个大小写英文字母还有数字再加上其他常用符号，也不到100个，因此使用7个比特位就可以高效的存储和处理ASCII码，剩下最高位1比特被用作一些通讯系统的奇偶校验。</p>
<blockquote><p>注意，字节代表系统能够处理的最小单位，不一定是8比特。只是现代计算机的事实标准就是用8比特来代表一个字节。在很多技术规格文献中，为了避免产生歧义，更倾向于使用8位组（Octet）而不是字节（Byte）这个术语来强调8个比特的二进制流。下文中为了便于理解，我会延用大家熟悉的“字节”这个概念。</p></blockquote>
<p><img style="display: inline; margin-left: 0px; margin-right: 0px;" src="http://www.joelonsoftware.com/pictures/unicode/ascii.png" alt="ASCII table" width="274" height="146" /></p>
<p>ASCII字符集由95个可打印字符（0x20-0x7E）和33个控制字符（0x00-0x19，0x7F）组成。可打印字符用于显示在输出设备上，例如荧屏或者打印纸上，控制字符用于向计算机发出一些特殊指令，例如0x07会让计算机发出哔的一声，0x00通常用于指示字符串的结束，0x0D和0x0A用于指示打印机的打印针头退到行首（回车）并移到下一行（换行）。</p>
<p>那时候的字符编解码系统非常简单，就是简单的查表过程。例如将字符序列编码为二进制流写入存储设备，只需要在ASCII字符集中依次找到字符对应的字节，然后直接将该字节写入存储设备即可。解码二进制流的过程也是类似。</p>
<h2>OEM字符集的衍生</h2>
<p>当计算机开始发展起来的时候，人们逐渐发现，ASCII字符集里那可怜的128个字符已经不能再满足他们的需求了。人们就在想，一个字节能够表示的数字（编号）有256个，而ASCII字符只用到了0x00~0x7F，也就是占用了前128个，后面128个数字不用白不用，因此很多人打起了后面这128个数字的主意。可是问题在于，很多人同时有这样的想法，但是大家对于0x80-0xFF这后面的128个数字分别对应什么样的字符，却有各自的想法。这就导致了当时销往世界各地的机器上出现了大量各式各样的OEM字符集。</p>
<p>下面这张表是IBM-PC机推出的其中一个OEM字符集，字符集的前128个字符和ASCII字符集的基本一致（为什么说基本一致呢，是因为前32个控制字符在某些情况下会被IBM-PC机当作可打印字符解释），后面128个字符空间加入了一些欧洲国家用到的重音字符，以及一些用于画线条画的字符。</p>
<p><img style="display: inline;" title="IBM-PC OEM字符集" src="http://www.joelonsoftware.com/pictures/unicode/oem.png" alt="IBM-PC OEM字符集" width="271" height="209" /></p>
<p>事实上，大部分OEM字符集是兼容ASCII字符集的，也就是说，大家对于0x00~0x7F这个范围的解释基本是相同的，而对于后半部分0x80~0xFF的解释却不一定相同。甚至有时候同样的字符在不同OEM字符集中对应的字节也是不同的。</p>
<p>不同的OEM字符集导致人们无法跨机器交流各种文档。例如职员甲发了一封简历résumés给职员乙，结果职员乙看到的却是r<img src="http://www.joelonsoftware.com/pictures/unicode/gimel.png" alt="?" width="5" height="9" />sum<img src="http://www.joelonsoftware.com/pictures/unicode/gimel.png" alt="?" width="5" height="9" />s，因为é字符在职员甲机器上的OEM字符集中对应的字节是0x82，而在职员乙的机器上，由于使用的OEM字符集不同，对0x82字节解码后得到的字符却是<img src="http://www.joelonsoftware.com/pictures/unicode/gimel.png" alt="?" width="5" height="9" />。</p>
<h2>多字节字符集（MBCS）和中文字符集</h2>
<p>上面我们提到的字符集都是基于单字节编码，也就是说，一个字节翻译成一个字符。这对于拉丁语系国家来说可能没有什么问题，因为他们通过扩展第8个比特，就可以得到256个字符了，足够用了。但是对于亚洲国家来说，256个字符是远远不够用的。因此这些国家的人为了用上电脑，又要保持和ASCII字符集的兼容，就发明了多字节编码方式，相应的字符集就称为多字节字符集。例如中国使用的就是双字节字符集编码（DBCS，Double Byte Character Set）。</p>
<p>对于单字节字符集来说，代码页中只需要有一张码表即可，上面记录着256个数字代表的字符。程序只需要做简单的查表操作就可以完成编解码的过程。</p>
<blockquote><p>代码页是字符集编码的具体实现，你可以把他理解为一张“字符-字节”映射表，通过查表实现“字符-字节”的翻译。下面会有更详细的描述。</p></blockquote>
<p>而对于多字节字符集，代码页中通常会有很多码表。那么程序怎么知道该使用哪张码表去解码二进制流呢？答案是，<strong>根据第一个字节来选择不同的码表进行解析</strong>。</p>
<p>例如目前最常用的中文字符集GB2312，涵盖了所有简体字符以及一部分其他字符；GBK（K代表扩展的意思）则在GB2312的基础上加入了对繁体字符等其他非简体字符（GB18030字符集不是双字节字符集，我们在讲Unicode的时候会提到）。这两个字符集的字符都是使用1-2个字节来表示。Windows系统采用936代码页来实现对GBK字符集的编解码。在解析字节流的时候，如果遇到字节的最高位是0的话，那么就使用936代码页中的第1张码表进行解码，这就和单字节字符集的编解码方式一致了。</p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image15.png" alt="image" width="416" height="305" /></p>
<p>当字节的高位是1的时候，确切的说，当第一个字节位于0x<code>81</code>–0x<code>FE之间时，根据第一个字节不同找到代码页中的相应的码表，例如当第一个字节是0x81，那么对应936中的下面这张码表：</code></p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image9.png" alt="image" width="442" height="374" /></p>
<p>（关于936代码页中完整的码表信息，参见MSDN：<a title="http://msdn.microsoft.com/en-us/library/cc194913%28v=MSDN.10%29.aspx" href="http://msdn.microsoft.com/en-us/library/cc194913%28v=MSDN.10%29.aspx">http://msdn.microsoft.com/en-us/library/cc194913%28v=MSDN.10%29.aspx</a>.）</p>
<p>按照936代码页的码表，当程序遇到连续字节流0x81 0x40的时候，就会解码为“丂”字符。</p>
<h2>ANSI标准、国家标准、ISO标准</h2>
<p>不同ASCII衍生字符集的出现，让文档交流变得非常困难，因此各种组织都陆续进行了标准化流程。例如美国ANSI组织制定了ANSI标准字符编码（注意，<strong>我们现在通常说到ANSI编码，通常指的是平台的默认编码，例如英文操作系统中是ISO-8859-1，中文系统是GBK</strong>），ISO组织制定的各种ISO标准字符编码，还有各国也会制定一些国家标准字符集，例如中国的GBK，GB2312和GB18030。</p>
<p>操作系统在发布的时候，通常会往机器里预装这些标准的字符集还有平台专用的字符集，这样只要你的文档是使用标准字符集编写的，通用性就比较高了。例如你用GB2312字符集编写的文档，在中国大陆内的任何机器上都能正确显示。同时，我们也可以在一台机器上阅读多个国家不同语言的文档了，前提是本机必须安装该文档使用的字符集。</p>
<h2>Unicode的出现</h2>
<p>虽然通过使用不同字符集，我们可以在一台机器上查阅不同语言的文档，但是我们仍然无法解决一个问题：<strong>在一份文档中显示所有字符</strong>。为了解决这个问题，我们需要一个全人类达成共识的巨大的字符集，这就是Unicode字符集。</p>
<h3>Unicode字符集概述</h3>
<p>Unicode字符集涵盖了目前人类使用的所有字符，并为每个字符进行统一编号，分配唯一的字符码（Code Point）。Unicode字符集将所有字符按照使用上的频繁度划分为17个层面（Plane），每个层面上有2<sup>16</sup>=65536个字符码空间。</p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image29.png" alt="image" width="556" height="224" /></p>
<p>其中第0个层面BMP，基本涵盖了当今世界用到的所有字符。其他的层面要么是用来表示一些远古时期的文字，要么是留作扩展。我们平常用到的Unicode字符，一般都是位于BMP层面上的。目前Unicode字符集中尚有大量字符空间未使用。</p>
<h3>编码系统的变化</h3>
<p>在Unicode出现之前，所有的字符集都是和具体编码方案绑定在一起的，都是直接将字符和最终字节流绑定死了，例如ASCII编码系统规定使用7比特来编码ASCII字符集；GB2312以及GBK字符集，限定了使用最多2个字节来编码所有字符，并且规定了字节序。这样的编码系统通常用简单的查表，也就是通过代码页就可以直接将字符映射为存储设备上的字节流了。例如下面这个例子：</p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image17.png" alt="image" width="373" height="275" /></p>
<p>这种方式的缺点在于，字符和字节流之间耦合得太紧密了，从而限定了字符集的扩展能力。假设以后火星人入住地球了，要往现有字符集中加入火星文就变得很难甚至不可能了，而且很容易破坏现有的编码规则。</p>
<p>因此Unicode在设计上考虑到了这一点，将字符集和字符编码方案分离开。</p>
<p><img style="display: inline;" title="字符编码系统" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image10.png" alt="字符编码系统" width="329" height="265" /></p>
<p>也就是说，<strong>虽然每个字符在Unicode字符集中都能找到唯一确定的编号（字符码，又称Unicode码），但是决定最终字节流的却是具体的字符编码</strong>。例如同样是对Unicode字符“A”进行编码，UTF-8字符编码得到的字节流是0x41，而UTF-16（大端模式）得到的是0x00 0x41。</p>
<h3>常见的Unicode编码</h3>
<p><strong>UCS-2/UTF-16</strong></p>
<p>如果要我们来实现Unicode字符集中BMP字符的编码方案，我们会怎么实现？由于BMP层面上有2<sup>16</sup>=65536个字符码，因此我们只需要两个字节就可以完全表示这所有的字符了。</p>
<p>举个例子，“中”的Unicode字符码是0x4E2D(01001110 00101101)，那么我们可以编码为01001110 00101101（大端）或者00101101 01001110 （小端）。</p>
<p>UCS-2和UTF-16对于BMP层面的字符均是使用2个字节来表示，并且编码得到的结果完全一致。不同之处在于，<strong>UCS-2最初设计的时候只考虑到BMP字符，因此使用固定2个字节长度，也就是说，他无法表示Unicode其他层面上的字符，而UTF-16为了解除这个限制，支持Unicode全字符集的编解码，采用了变长编码，最少使用2个字节，如果要编码BMP以外的字符，则需要4个字节结对</strong>，这里就不讨论那么远，有兴趣可以参考维基百科：<a title="UTF-16/UCS-2" href="http://en.wikipedia.org/wiki/UTF-16/UCS-2" target="_blank">UTF-16/UCS-2</a>。</p>
<p>Windows从NT时代开始就采用了UTF-16编码，很多流行的编程平台，例如.Net，Java，Qt还有Mac下的Cocoa等都是使用UTF-16作为基础的字符编码。例如代码中的字符串，在内存中相应的字节流就是用UTF-16编码过的。</p>
<p><strong>UTF-8</strong></p>
<p>UTF-8应该是目前应用最广泛的一种Unicode编码方案。由于UCS-2/UTF-16对于ASCII字符使用两个字节进行编码，存储和处理效率相对低下，并且由于ASCII字符经过UTF-16编码后得到的两个字节，高字节始终是0x00，很多C语言的函数都将此字节视为字符串末尾从而导致无法正确解析文本。因此一开始推出的时候遭到很多西方国家的抵触，大大影响了Unicode的推行。后来聪明的人们发明了UTF-8编码，解决了这个问题。</p>
<p>UTF-8编码方案采用1-4个字节来编码字符，方法其实也非常简单。</p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image11.png" alt="image" width="492" height="345" /></p>
<p>（上图中的x代表Unicode码的低8位，y代表高8位）</p>
<p><strong>对于ASCII字符的编码使用单字节，和ASCII编码一摸一样，这样所有原先使用ASCII编解码的文档就可以直接转到UTF-8编码了。对于其他字符，则使用2-4个字节来表示，其中，首字节前置1的数目代表正确解析所需要的字节数，剩余字节的高2位始终是10。例如首字节是1110yyyy，前置有3个1，说明正确解析总共需要3个字节，需要和后面2个以10开头的字节结合才能正确解析得到字符</strong>。</p>
<p>关于UTF-8的更多信息，参考维基百科：<a title="UTF-8" href="http://en.wikipedia.org/wiki/UTF-8" target="_blank">UTF-8</a>。</p>
<p><strong>GB18030</strong></p>
<p>任何能够将Unicode字符映射为字节流的编码都属于Unicode编码。中国的GB18030编码，覆盖了Unicode所有的字符，因此也算是一种Unicode编码。只不过他的编码方式并不像UTF-8或者UTF-16一样，将Unicode字符的编号通过一定的规则进行转换，而只能通过查表的手段进行编码。</p>
<p>关于GB18030的更多信息，参考：<a title="GB18030" href="http://en.wikipedia.org/wiki/GB18030" target="_blank">GB18030</a>。</p>
<h3>Unicode相关的常见问题</h3>
<p><strong>Unicode是两个字节吗？</strong></p>
<p>Unicode只是定义了一个庞大的、全球通用的字符集，并为每个字符规定了唯一确定的编号，具体存储为什么样的字节流，取决于字符编码方案。推荐的Unicode编码是UTF-16和UTF-8。</p>
<p><strong>带签名的UTF-8指的是什么意思？</strong></p>
<p>带签名指的是字节流以BOM标记开始。很多软件会“智能”的探测当前字节流使用的字符编码，这种探测过程出于效率考虑，通常会提取字节流前面若干个字节，看看是否符合某些常见字符编码的编码规则。由于UTF-8和ASCII编码对于纯英文的编码是一样的，无法区分开来，因此通过在字节流最前面添加BOM标记可以告诉软件，当前使用的是Unicode编码，判别成功率就十分准确了。但是需要注意，不是所有软件或者程序都能正确处理BOM标记，例如PHP就不会检测BOM标记，直接把它当普通字节流解析了。因此如果你的PHP文件是采用带BOM标记的UTF-8进行编码的，那么有可能会出现问题。</p>
<p><strong>Unicode编码和以前的字符集编码有什么区别？</strong></p>
<p>早期字符编码、字符集和代码页等概念都是表达同一个意思。例如GB2312字符集、GB2312编码，936代码页，实际上说的是同个东西。但是对于Unicode则不同，Unicode字符集只是定义了字符的集合和唯一编号，Unicode编码，则是对UTF-8、UCS-2/UTF-16等具体编码方案的统称而已，并不是具体的编码方案。所以当需要用到字符编码的时候，你可以写gb2312，codepage936，utf-8，utf-16，但请不要写unicode（看过别人在网页的meta标签里头写charset=unicode，有感而发）。</p>
<h2>乱码问题</h2>
<p>乱码指的是程序显示出来的字符文本无法用任何语言去解读。一般情况下会包含大量<img class="size-full wp-image-1847" title="symbol" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/symbol.jpg" alt="解码失败替换字符" width="16" height="17" />或者?。乱码问题是所有计算机用户或多或少会遇到的问题。<strong>造成乱码的原因就是因为使用了错误的字符编码去解码字节流</strong>，<strong>因此当我们在思考任何跟文本显示有关的问题时，请时刻保持清醒：当前使用的字符编码是什么</strong>。只有这样，我们才能正确分析和处理乱码问题。</p>
<p>例如最常见的网页乱码问题。如果你是网站技术人员，遇到这样的问题，需要检查以下原因：</p>
<ul>
<li>服务器返回的响应头Content-Type没有指明字符编码</li>
<li>网页内是否使用META HTTP-EQUIV标签指定了字符编码</li>
<li>网页文件本身存储时使用的字符编码和网页声明的字符编码是否一致</li>
</ul>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image12.png" alt="image" width="209" height="121" /> <img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image51.png" alt="image" width="369" height="66" /></p>
<p>注意，网页解析的过程如果使用的字符编码不正确，还可能会导致脚本或者样式表出错。具体细节可以参考我以前写过的文章：<a href="http://www.imkevinyang.com/2009/08/%E6%96%87%E6%A1%A3%E5%AD%97%E7%AC%A6%E9%9B%86%E5%AF%BC%E8%87%B4%E7%9A%84%E8%84%9A%E6%9C%AC%E9%94%99%E8%AF%AF.html">文档字符集导致的脚本错误</a>和<a href="http://www.imkevinyang.com/2009/11/asp-net%E9%A1%B5%E9%9D%A2%E7%9A%84%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98.html">Asp.Net页面的编码问题</a>。</p>
<p>不久前看到某技术论坛有人反馈，WinForm程序使用Clipboard类的GetData方法去访问剪切板中的HTML内容时会出现乱码的问题，我估计也是由于WinForm在获取HTML文本的时候没有用对正确的字符编码导致的。Windows剪贴板只支持UTF-8编码，也就是说你传入的文本都会被UTF-8编解码。这样一来，只要两个程序都是调用Windows剪切板API编程的话，那么复制粘贴的过程中不会出现乱码。除非一方在获取到剪贴板数据之后使用了错误的字符编码进行解码，才会得到乱码（我做了简单的WinForm剪切板编程实验，发现GetData使用的是系统默认编码，而不是UTF-8编码）。</p>
<p>关于乱码中出现?或者?，这里需要额外提一下，<strong>当程序使用特定字符编码解析字节流的时候，一旦遇到无法解析的字节流时，就会用<img title="symbol" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/symbol.jpg" alt="解码失败替换字符" width="16" height="17" />或者?来替代。因此，一旦你最终解析得到的文本包含这样的字符，而你又无法得到原始字节流的时候，说明正确的信息已经彻底丢失了，尝试任何字符编码都无法从这样的字符文本中还原出正确的信息来</strong>。</p>
<h2>必要的术语解释</h2>
<p><strong>字符集（Character Set）</strong>，字面上的理解就是字符的集合，例如ASCII字符集，定义了128个字符；GB2312定义了7445个字符。而<strong>计算机系统中提到的字符集准确来说，指的是已编号的字符的有序集合（不一定是连续）</strong>。</p>
<p><strong>字符码（Code Point）</strong>指的就是字符集中每个字符的数字编号。例如ASCII字符集用0-127这连续的128个数字分别表示128个字符；GBK字符集使用区位码的方式为每个字符编号，首先定义一个94X94的矩阵，行称为“区”，列称为“位”，然后将所有国标汉字放入矩阵当中，这样每个汉字就可以用唯一的“区位”码来标识了。例如“中”字被放到54区第48位，因此字符码就是5448。而Unicode中将字符集按照一定的类别划分到0~16这17个层面（Planes）中，每个层面中拥有2<sup>16</sup>=65536个字符码，因此Unicode总共拥有的字符码，也即是Unicode的字符空间总共有17*65536=1114112。</p>
<p><sup> </sup></p>
<p><img style="display: inline;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/06/image24.png" alt="image" width="218" height="199" /></p>
<p><strong>编码</strong>的过程是将字符转换成字节流。</p>
<p><strong>解码</strong>的过程是将字节流解析为字符。</p>
<p><strong>字符编码（Character Encoding）</strong>是将字符集中的字符码映射为字节流的一种具体实现方案。例如ASCII字符编码规定使用单字节中低位的7个比特去编码所有的字符。例如‘A’的编号是65，用单字节表示就是0x41，因此写入存储设备的时候就是b’01000001’。GBK编码则是将区位码（GBK的字符码）中的区码和位码的分别加上0xA0（160）的偏移（之所以要加上这样的偏移，主要是为了和ASCII码兼容），例如刚刚提到的“中”字，区位码是5448，十六进制是0x3630，区码和位码分别加上0xA0的偏移之后就得到0xD6D0，这就是“中”字的GBK编码结果。</p>
<p><strong>代码页（Code Page）</strong>一种字符编码具体形式。早期字符相对少，因此通常会使用类似表格的形式将字符直接映射为字节流，然后通过查表的方式来实现字符的编解码。现代操作系统沿用了这种方式。例如Windows使用936代码页、Mac系统使用EUC-CN代码页实现GBK字符集的编码，名字虽然不一样，但对于同一汉字的编码肯定是一样的。</p>
<p><strong>大小端</strong>的说法源自《格列佛游记》。我们知道，鸡蛋通常一端大一端小，小人国的人们对于剥蛋壳时应从哪一端开始剥起有着不一样的看法。同样，计算机界对于传输多字节字（由多个字节来共同表示一个数据类型）时，是先传高位字节（大端）还是先传低位字节（小端）也有着不一样的看法，这就是计算机里头大小端模式的由来了。无论是写文件还是网络传输，实际上都是往流设备进行写操作的过程，而且这个写操作是从流的低地址向高地址开始写（这很符合人的习惯），对于多字节字来说，如果先写入高位字节，则称作大端模式。反之则称作小端模式。也就是说，大端模式下，字节序和流设备的地址顺序是相反的，而小端模式则是相同的。一般网络协议都采用大端模式进行传输，windows操作系统采用Utf-16小端模式。</p>
<p style="text-align: right;">——<a title="关于字符编码，你所需要知道的" href="http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html"><em><strong>Kevin Yang</strong></em></a></p>
<p>参考链接：</p>
<ul>
<li><a title="The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)" href="http://www.joelonsoftware.com/printerFriendly/articles/Unicode.html" target="_blank">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)</a></li>
<li><a title="http://developers.sun.com/dev/gadc/technicalpublications/articles/gb18030.html" href="http://developers.sun.com/dev/gadc/technicalpublications/articles/gb18030.html">http://developers.sun.com/dev/gadc/technicalpublications/articles/gb18030.html</a></li>
<li><a title="http://en.wikipedia.org/wiki/Universal_Character_Set" href="http://en.wikipedia.org/wiki/Universal_Character_Set">http://en.wikipedia.org/wiki/Universal_Character_Set</a></li>
<li><a title="http://en.wikipedia.org/wiki/Code_page" href="http://en.wikipedia.org/wiki/Code_page">http://en.wikipedia.org/wiki/Code_page</a></li>
</ul>

	标签：<a href="http://www.imkevinyang.com/tags/ascii" title="ASCII" rel="tag">ASCII</a>, <a href="http://www.imkevinyang.com/tags/gb18030" title="GB18030" rel="tag">GB18030</a>, <a href="http://www.imkevinyang.com/tags/gb2312" title="GB2312" rel="tag">GB2312</a>, <a href="http://www.imkevinyang.com/tags/gbk" title="GBK" rel="tag">GBK</a>, <a href="http://www.imkevinyang.com/tags/oem" title="OEM" rel="tag">OEM</a>, <a href="http://www.imkevinyang.com/tags/unicode" title="Unicode" rel="tag">Unicode</a>, <a href="http://www.imkevinyang.com/tags/utf-16" title="UTF-16" rel="tag">UTF-16</a>, <a href="http://www.imkevinyang.com/tags/utf-8" title="UTF-8" rel="tag">UTF-8</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6" title="字符" rel="tag">字符</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81" title="字符编解码" rel="tag">字符编解码</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e7%a0%81" title="编码" rel="tag">编码</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html" title="Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8） (2009/04/28)">Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/php%e5%a4%84%e7%90%86bom%e6%a0%87%e8%ae%b0%e7%9a%84utf-8%e6%96%87%e4%bb%b6%e5%af%bc%e8%87%b4%e7%9a%84%e9%97%ae%e9%a2%98.html" title="PHP处理BOM标记的UTF-8文件导致的问题 (2009/05/05)">PHP处理BOM标记的UTF-8文件导致的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html" title="字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别） (2009/02/28)">字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e5%ad%97%e7%ac%a6%ef%bc%8c%e5%ad%97%e8%8a%82%e5%92%8c%e7%bc%96%e7%a0%81.html" title="字符，字节和编码 (2009/11/27)">字符，字节和编码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" title="文档字符集导致的脚本错误 (2009/08/19)">文档字符集导致的脚本错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决Xaml中包含中文导致无法编译的问题 (2009/09/29)">解决Xaml中包含中文导致无法编译的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Win7/Vista高级用户必备的右键菜单Take back my Ownership!</title>
		<link>http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html</link>
		<comments>http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html#comments</comments>
		<pubDate>Sun, 06 Dec 2009 06:19:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[UAC]]></category>
		<category><![CDATA[Vista]]></category>
		<category><![CDATA[Win7]]></category>
		<category><![CDATA[右键菜单]]></category>
		<category><![CDATA[微软]]></category>
		<category><![CDATA[权限]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html</guid>
		<description><![CDATA[<p>从Vista开始，Windows的权限控制就更为严格了，微软还很自豪地引入了UAC的功能。但结果却是让更多人讨厌这个系统（相信很多人都像我一样为了图省事直接把UAC关了）。Win7在权限控制上相比Vista稍微松了一点，但还是经常会出现很脑残的行为。</p>
<p>我曾经在整理电脑上的文件的时候，想删除某个软件的安&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>从Vista开始，Windows的权限控制就更为严格了，微软还很自豪地引入了UAC的功能。但结果却是让更多人讨厌这个系统（相信很多人都像我一样为了图省事直接把UAC关了）。Win7在权限控制上相比Vista稍微松了一点，但还是经常会出现很脑残的行为。</p>
<p>我曾经在整理电脑上的文件的时候，想删除某个软件的安装目录，但是却弹出一个窗口，提示我“此操作需要提供管理员权限”。但是窗口上只有一个“重试”和“取消”的按钮，你点重试吧，他会提示你一样的问题，最后你还是不得不点取消。没有一个地方可以允许你已管理员的身份去执行这个删除的操作（对于exe程序，win7倒是提供了一个以管理员身份运行的右键菜单）。对于windows下有经验的用户，一般会尝试打开文件夹的属性，切换到“安全”选项卡，然后添加自己的权限。然后再去删。有时候可以成功，但有时候我却遇到了另外一个错误。“当前操作需要Kevin的权限才能进行”（我当前使用的用户名就是Kevin）。吐血身亡…..</p>
<p><a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>了一把，说是ownership（所有权）导致的问题，只要把文件/文件夹的所有权改成自己就没问题了。具体为什么我也懒得去研究了，这种弱智的问题研究透了也只能说明自己也是一个弱智。网上有人提供了一个注册表脚本，可以在右键集成一个“Take ownership”的菜单，这样当遇到类似的权限问题就直接要回所有权就行了。</p>
<p>新建一个install.reg的文件，用记事本打开，然后将下面的内容拷贝到文件中，然后双击导入注册表即可。</p>
<pre class="csharpcode">

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\runas]
@=<span class="str">&quot;Take Ownership&quot;</span>
<span class="str">&quot;NoWorkingDirectory&quot;</span>=<span class="str">&quot;&quot;</span>

[HKEY_CLASSES_ROOT\*\shell\runas\command]
@=<span class="str">&quot;cmd.exe /c takeown /f \&quot;%1\&quot; &amp;&amp; icacls \&quot;%1\&quot; /grant administrators:F&quot;</span>
<span class="str">&quot;IsolatedCommand&quot;</span>=<span class="str">&quot;cmd.exe /c takeown /f \&quot;%1\&quot; &amp;&amp; icacls \&quot;%1\&quot; /grant administrators:F&quot;</span>

[HKEY_CLASSES_ROOT\Directory\shell\runas]
@=<span class="str">&quot;Take Ownership&quot;</span>
<span class="str">&quot;NoWorkingDirectory&quot;</span>=<span class="str">&quot;&quot;</span>

[HKEY_CLASSES_ROOT\Directory\shell\runas\command]
@=<span class="str">&quot;cmd.exe /c takeown /f \&quot;%1\&quot; /r /d y &amp;&amp; icacls \&quot;%1\&quot; /grant administrators:F /t&quot;</span>
<span class="str">&quot;IsolatedCommand&quot;</span>=<span class="str">&quot;cmd.exe /c takeown /f \&quot;%1\&quot; /r /d y &amp;&amp; icacls \&quot;%1\&quot; /grant administrators:F /t&quot;</span>

<span class="str"></span>&#160;
</pre>
<p>实际效果如下图所示：</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Take owership" border="0" alt="Take owership" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb3.png" width="244" height="123" />&#160;</p>
<p>参考链接：</p>
<p><a href="http://www.howtogeek.com/howto/windows-vista/add-take-ownership-to-explorer-right-click-menu-in-vista/">http://www.howtogeek.com/howto/windows-vista/add-take-ownership-to-explorer-right-click-menu-in-vista/</a></p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/uac" title="UAC" rel="tag">UAC</a>, <a href="http://www.imkevinyang.com/tags/vista" title="Vista" rel="tag">Vista</a>, <a href="http://www.imkevinyang.com/tags/win7" title="Win7" rel="tag">Win7</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95" title="右键菜单" rel="tag">右键菜单</a>, <a href="http://www.imkevinyang.com/tags/microsoft" title="微软" rel="tag">微软</a>, <a href="http://www.imkevinyang.com/tags/%e6%9d%83%e9%99%90" title="权限" rel="tag">权限</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/05/google%e5%92%8c%e5%be%ae%e8%bd%af%e7%9a%84%e4%b8%80%e5%a4%a7%e4%b8%8d%e5%90%8c.html" title="Google和微软的一大不同 (2009/05/06)">Google和微软的一大不同</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/vs2010%e7%9a%84ui%e8%ae%be%e8%ae%a1%e5%a4%b1%e8%af%af.html" title="VS2010的UI设计失误 (2010/05/31)">VS2010的UI设计失误</a> </li>
	<li><a href="http://www.imkevinyang.com/2011/01/win7%e7%ae%a1%e7%90%86%e6%97%a0%e7%ba%bf%e7%bd%91%e7%bb%9c%e5%8f%98%e6%88%90%e5%b0%8f%e5%9b%be%e6%a0%87%e4%ba%86.html" title="Win7管理无线网络变成小图标了 (2011/01/04)">Win7管理无线网络变成小图标了</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/win7%e8%ae%bf%e9%97%ae%e8%bf%9c%e7%a8%8b%e6%a1%8c%e9%9d%a2%e6%9c%80%e5%a4%a7%e5%8c%96%e5%90%8c%e6%97%b6%e8%ae%a9%e4%bb%bb%e5%8a%a1%e6%a0%8f%e5%8f%af%e8%a7%81.html" title="Win7访问远程桌面最大化同时让任务栏可见 (2010/07/03)">Win7访问远程桌面最大化同时让任务栏可见</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/%e5%8d%81%e5%b9%b4mfc%e7%bb%8f%e5%8e%86%e8%ae%a4%e8%af%86%e7%9a%84microsoft%e6%8a%80%e6%9c%af.html" title="十年MFC经历认识的Microsoft技术 (2009/03/17)">十年MFC经历认识的Microsoft技术</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/11/%e5%be%ae%e8%bd%afazure%e5%b9%b3%e5%8f%b0%e7%9a%84%e8%ae%a1%e8%b4%b9%e6%a8%a1%e5%9e%8b.html" title="微软Azure平台的计费模型 (2010/11/12)">微软Azure平台的计费模型</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%be%ae%e8%bd%af%e6%8a%80%e6%9c%af%e7%a4%be%e5%8c%ba%e7%b2%be%e8%8b%b1%e8%ae%a1%e5%88%92%e4%bd%a0%e4%b9%9f%e6%9d%a5%e5%8a%a0%e5%85%a5%e5%90%a7.html" title="微软技术社区精英计划&mdash;&mdash;你也来加入吧 (2010/06/02)">微软技术社区精英计划&mdash;&mdash;你也来加入吧</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html" title="权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题 (2009/11/12)">权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e8%a7%a3%e5%86%b3win7%e4%b8%8bie8%e5%bc%80%e5%8f%91%e4%ba%ba%e5%91%98%e5%b7%a5%e5%85%b7%e7%aa%97%e5%8f%a3%e6%b6%88%e5%a4%b1%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决Win7下IE8开发人员工具打不开的问题 (2009/11/13)">解决Win7下IE8开发人员工具打不开的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2011/05/%e8%a7%a3%e5%86%b3%e6%96%b0%e5%88%9b%e5%bb%ba%e7%9a%84windows%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%aetfs%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决新创建的windows用户无法访问TFS的问题 (2011/05/12)">解决新创建的windows用户无法访问TFS的问题</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Wave为什么这么火</title>
		<link>http://www.imkevinyang.com/2009/11/google-wave%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e7%81%ab.html</link>
		<comments>http://www.imkevinyang.com/2009/11/google-wave%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e7%81%ab.html#comments</comments>
		<pubDate>Sat, 14 Nov 2009 06:10:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[生活网事]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Google Wave]]></category>
		<category><![CDATA[Wave]]></category>
		<category><![CDATA[会话]]></category>
		<category><![CDATA[富媒体]]></category>
		<category><![CDATA[用户体验]]></category>
		<category><![CDATA[电子邮件]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/google-wave%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e7%81%ab.html</guid>
		<description><![CDATA[<p><a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> Wave是<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>目前力推的一个产品，老在很多地方看到有关Wave的介绍，无奈Wave采用的是和当年Gmail一样的邀请策略，除非有人邀请你，否则你通过注册申请的方式，需要等待很长一段时间才能生效。国庆的时候很幸运的我的申请很快就被批准了，还获得了20个邀请名额，开始投身Wave试用&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> Wave是<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>目前力推的一个产品，老在很多地方看到有关Wave的介绍，无奈Wave采用的是和当年Gmail一样的邀请策略，除非有人邀请你，否则你通过注册申请的方式，需要等待很长一段时间才能生效。国庆的时候很幸运的我的申请很快就被批准了，还获得了20个邀请名额，开始投身Wave试用大军。</p>
<p>之前看<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> IO大会上对Wave铺天盖地的介绍，觉得<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>这次推的概念确实很不错。</p>
<blockquote><p>如果电子邮件不是在30年前发明的，而是今天发明的，那么它应该就是Wave现在这个样子。</p>
</blockquote>
<h2>传统电子邮件的局限</h2>
<p>当你使用电子邮件的时候，你每发送一封邮件，邮件在你这边存了一份，然后在别人那边也存了一份，邮件与邮件之间是非常独立的。如果你要知道别人回复邮件的上下文，你需要在收件箱里面查找以前的邮件，当然，现在几乎所有的邮件客户端都会在你回复的时候把收到的邮件拷贝一份附加到正文末尾，然后发给对方，这样别人就可以在一封邮件中找到上下文了，代价就是，邮件会越来越庞大。</p>
<p>当邮件交流比较少的时候，这不是什么大问题。但是当邮件比较多的时候，你就很容易迷失在收件箱或者杂乱的邮件内容中。后来Gmail创新性的推出了“邮件会话”的概念，它把同一个主题的邮件组合到了一起，这样当你隔了好几天收到别人邮件的时候，你就可以在同一个界面中看到邮件主题讨论的全部过程了。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb12.png" width="364" height="150" /> </p>
<p>但是假设后面有个人C加入了A和B这个会话主题，那么他就无法知道A和B之前讨论过什么样的内容，除非A或者B把之前的邮件内容都发送给C。这是非常麻烦的。</p>
<h2>画布式的交流取代扔球式的交流</h2>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="left" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb13.png" width="243" height="244" />&#160;<img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="right" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb14.png" width="244" height="208" /> </p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>本来想取个中规中矩的标题，但后来想还是上面这个标题形象点。</p>
<p>传统的电子邮件交流方式就好像两个人玩扔球一样，两个人把要说的话写到球上，然后扔给对方，对方只有等到你把球扔过来才能知道你要说什么，如果要附带一些其他的东西的话，还得绑到球上扔过去，一旦过重还没法扔呢（现在的邮件要带上个3M的附件就很难发送了）。</p>
<p>而Wave提倡的方式是画布式的交流方式，当你想讨论一个主题的时候，你就好比放一块画布在那，然后所有你希望加入这个主题的人都可以直接在上面“画”任何东西。这就意味着，如果有个人后来才加入你这个主题的，那么他依然可以看到整个主题的全貌。</p>
<p>但是这里有个问题，假设有几个人合作在画布上画了蒙娜丽莎，哇，令人叹为观止，虽然后面加入的人可以看到整幅蒙娜丽莎的画像，但是他无法知道别人都是怎么开始画的。</p>
<h2>会话回放</h2>
<p>Wave借用了视频回放的概念，引入了“主题回放”（Playback）的功能，你可以在上面重新回放别人整个交流过程，就好像看视频重播一样。你可以看到一开始XXX挖了个坑，然后YYY非常挑衅的发表了什么高论，然后被ZZZ等人狂批了一顿，后来YYY自觉羞辱，就把之前发表的高论删了。。。。所以尽管你是后来的，但是你依然不会落下会话的每个细节。</p>
<h2>Wave的画布可以“画”什么？</h2>
<p>Wave可以做什么？</p>
<p>你可以把他当作一个即时交流工具或者早期的聊天室。在上面搜索你感兴趣的话题，然后加入。你也可以把他当作论坛、BBS来用。你甚至可以把他当作一个协作平台，在上面进行多人创作。</p>
<p>Web2.0是一个富媒体的时代，传统电子邮件的方式一般只能做文本交流，高级一点你可以在上面加些图片。但Wave希望未来的交流可不是这么枯燥。他希望你可以在上面以更多的方式进行交流，他希望把现在互联网上很多丰富的元素无缝的整合到Wave中来。</p>
<p>例如你和你朋友讨论到了一首歌，你可以从把这首歌放到Wave上面，这样两个人都可以在上面直接听到这首歌的播放，或者拖个视频进来，直接在上面看视频。</p>
<p>又例如，当你们讨论到一个话题无法得出结论的时候，你们可以在上面创建一个投票，这个投票可不是纯人肉统计的那种投票，而是在上面创建一个非常直观的投票器。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb15.png" width="272" height="145" /> </p>
<p>又例如，你朋友问你XXX地方在哪，地图那么大，不好找，这个时候你怎么告诉他具体在地图上的哪个位置呢？在以前，你可能会先告诉他是哪个省哪个市的，最多你会截个图发给他。在wave上呢，你可以拖一个<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>地图进来，然后在上面进行缩放导航，找到XXX这个地方之后在上面画个圈圈。注意，你的朋友可不是只看到最终的结果，他能看到你操作的整个过程！有趣吧~</p>
<p>下面这段视频挺有意思的：<a title="Google Wave的强大应用" href="http://v.youku.com/v_show/id_XMTI3MzM2MTQw.html" target="_blank">Google Wave的强大应用</a></p>
<h2>跨语言的交流</h2>
<p>由于Wave是一个开放的系统，大家都可以在上面开发各种各样的小插件。IO大会上演示了一个非常有意思的即时翻译插件。这个插件在Wave上看上去像一个普通的联系人，当你把这个“人”加入到你的会话中，它就可以帮助不同语言的人在交流的时候，自动将对方的语言转换成自己的母语。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb16.png" width="299" height="163" /> </p>
<p>先不管这个翻译质量如何，这个创意确实让人感到非常兴奋！</p>
<h2>Wave的画布有多大？</h2>
<p>你可能在想，我创建了一块“画布”（主题），别人怎么共享我的这块画布呢？当然，如果全世界都只用<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>的产品那事情就简单很多了。可实际情况是，网络中已经有太多交流协作的系统了，你无法让所有用户都改变他们的习惯，转移到Wave上来。因此<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a>设想的是把这块画布延伸到互联网各个角落，各个系统上。也就是说，你可以在Wave上创建一个主题（主题？画布？我想说的是一个意思）， 然后把这个主题实时更新到你的博客上，你的twitter上，你的iphone上，等等。<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> Wave是一个开放的系统架构，不同人搭建起来的Wave系统可以互相通讯。就好像不同的邮件服务器之间可以互相通讯一样。所以你如果问<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> Wave提供的画布有多大，这个问题还真不好回答~</p>
<h2>Preview版本的试用体验</h2>
<p>Wave现在还只是测试版本，试用了一段时间之后发现和我的期望并不是很相近。</p>
<h3>整体的用户体验</h3>
<p>从UI上来说，感觉Wave不是那么容易上手，像我这样的IT前沿分子（别喷我~）如果不看别人的教程，基本摸不着边。虽然在<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">Google</a> Wave上可以放置各种富媒体元素，但是不好好看教程，根本不知道怎么在上面放一个视频，怎么在上面放一个<a href="http://www.imkevinyang.com/tags/google" class="st_tag internal_tag" rel="tag" title="Posts tagged with Google">google</a> map。连最基本的设置个人信息我都找了半天。</p>
<p>Web应用应该以直观、简单为导向，就好像一本UI书的书名一样“Dont make me think”， 感觉Wave却是完全反着来做了。</p>
<p>目前的界面响应性能还是很糟糕的，在Chrome上经常用一会就很卡了。</p>
<h3>实时更新</h3>
</p>
</p>
<p>在Wave上，你输入的东西是会实时更新到其他地方的，例如你的Wave连着你的博客，或者有人正在搜索你创建的Wave主题，当你在Wave中输入一些信息的时候，这些信息会实时更新到你的博客上，别人的搜索结果上。</p>
<p>如果两个人在同一个Wave上，你可以看到别人敲字的过程，非常好玩。但这也仅仅是非常好玩而已。我相信不是很多中文用户会喜欢这个功能。因为中文输入法经常会根据你输入的词进行智能联想，如果你不小心打错了什么字母结果出来另外一个“有损形象”的词的话，那后果。。。我就不说了，呵呵</p>
<h3>版本控制非常糟糕</h3>
<p>Wave允许你自由编辑别人敲的内容，这很容易导致别人不小心弄乱你编写的内容。虽然Wave声称可以回放整个会话过程，并给其中的某一时刻起一个版本之类的，但是我并没有在界面上找到任何关于编辑权限控制的地方，除了那个Private Reply之外。</p>
<h3>会话顺序很混乱</h3>
<p>在一个wave中（一个wave就是一个主题，就是我说的一块“画布”），你可以自由的对某一条信息进行回复，回复的信息是直接嵌入到那一条信息之下的，而不是整个会话的最底部。这个设计对于浏览整个会话来说倒是很直观的，但是如果两个人在即时交流，你回复这条内容，我又回复你那条内容，很容易乱套了，除非用回放的功能，否则你无法实时知道别人最后说的什么。</p>
<p>以上就是我试用了一个月的一个粗糙的体验，可能有些地方理解得不对，有用过Wave的人互相交流一下吧。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/google" title="Google" rel="tag">Google</a>, <a href="http://www.imkevinyang.com/tags/google-wave" title="Google Wave" rel="tag">Google Wave</a>, <a href="http://www.imkevinyang.com/tags/wave" title="Wave" rel="tag">Wave</a>, <a href="http://www.imkevinyang.com/tags/%e4%bc%9a%e8%af%9d" title="会话" rel="tag">会话</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%af%8c%e5%aa%92%e4%bd%93" title="富媒体" rel="tag">富媒体</a>, <a href="http://www.imkevinyang.com/categories/dailylife" title="生活网事" rel="tag">生活网事</a>, <a href="http://www.imkevinyang.com/tags/%e7%94%a8%e6%88%b7%e4%bd%93%e9%aa%8c" title="用户体验" rel="tag">用户体验</a>, <a href="http://www.imkevinyang.com/tags/%e7%94%b5%e5%ad%90%e9%82%ae%e4%bb%b6" title="电子邮件" rel="tag">电子邮件</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/08/4%e8%a1%8cgreasemonkey%e4%bb%a3%e7%a0%81%e6%9c%80%e5%a4%a7%e5%8c%96google-reader%e7%9a%84%e9%98%85%e8%af%bb%e7%a9%ba%e9%97%b4.html" title="4行Greasemonkey代码最大化Google Reader的阅读空间 (2009/08/09)">4行Greasemonkey代码最大化Google Reader的阅读空间</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/03/android%e6%89%8b%e6%9c%ba%e5%88%9d%e4%bd%93%e9%aa%8c.html" title="Android手机初体验 (2010/03/01)">Android手机初体验</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/03/g1%e6%89%8b%e6%9c%ba%e4%b8%8e%e7%ac%94%e8%ae%b0%e6%9c%ac%e5%ae%9e%e7%8e%b0wifi%e4%ba%92%e8%81%94%e5%85%b1%e4%ba%ab%e4%b8%8a%e7%bd%91.html" title="G1手机与笔记本实现Wifi互联共享上网 (2010/03/02)">G1手机与笔记本实现Wifi互联共享上网</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/12/google-analytics%e4%b8%ad%e7%9a%84uniquepageview%e5%92%8cvisits%e7%9a%84%e5%8c%ba%e5%88%ab.html" title="Google Analytics中的UniquePageView和Visits的区别 (2009/12/07)">Google Analytics中的UniquePageView和Visits的区别</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/google%e5%92%8c%e5%be%ae%e8%bd%af%e7%9a%84%e4%b8%80%e5%a4%a7%e4%b8%8d%e5%90%8c.html" title="Google和微软的一大不同 (2009/05/06)">Google和微软的一大不同</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/google%e5%b7%a5%e7%a8%8b%e5%b8%88matt-cutts%e8%b0%88seo.html" title="Google工程师Matt Cutts谈SEO (2009/03/23)">Google工程师Matt Cutts谈SEO</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/google%e6%8e%92%e5%90%8d%e6%9b%b4%e6%96%b0.html" title="Google排名更新 (2009/03/21)">Google排名更新</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/google%e7%9a%84%e4%bb%b7%e5%80%bc%e8%a7%82.html" title="Google的价值观 (2009/03/07)">Google的价值观</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/02/%e4%bd%bf%e7%94%a8feedburner%e7%83%a7%e5%88%b6rss%e6%9c%80%e5%a5%bd%e7%a6%81%e7%94%a8itemlinkclicks%e7%bb%9f%e8%ae%a1.html" title="使用FeedBurner烧制RSS最好禁用ItemLinkClicks统计 (2010/02/15)">使用FeedBurner烧制RSS最好禁用ItemLinkClicks统计</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%86%85%e7%89%9b%e6%bb%a1%e9%9d%a2%ef%bc%8c%e7%bb%88%e4%ba%8e%e6%9c%89pr%e5%80%bc%e4%ba%86.html" title="内牛满面，终于有PR值了~ (2009/10/31)">内牛满面，终于有PR值了~</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/google-wave%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e7%81%ab.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>慎用类型强制转换</title>
		<link>http://www.imkevinyang.com/2009/11/%e6%85%8e%e7%94%a8%e7%b1%bb%e5%9e%8b%e5%bc%ba%e5%88%b6%e8%bd%ac%e6%8d%a2.html</link>
		<comments>http://www.imkevinyang.com/2009/11/%e6%85%8e%e7%94%a8%e7%b1%bb%e5%9e%8b%e5%bc%ba%e5%88%b6%e8%bd%ac%e6%8d%a2.html#comments</comments>
		<pubDate>Thu, 12 Nov 2009 06:06:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[类型转换]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/%e6%85%8e%e7%94%a8%e7%b1%bb%e5%9e%8b%e5%bc%ba%e5%88%b6%e8%bd%ac%e6%8d%a2.html</guid>
		<description><![CDATA[<p>类型转换是我们写代码经常需要打交道的事情，C#中类型转换有两种常见的形式：</p>
<p>(BaseClass)obj </p>
<p>obj <span class="kwrd">as</span> BaseClass</p>
<p>同时，Convert类也提供了很多常用类型的转换接口。</p>
<p>我接下来要说的是第一种转换形式。</p>
<p>当使用第一种转换形式的时候，要求obj是null，或者是一个BaseClass类或其&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>类型转换是我们写代码经常需要打交道的事情，C#中类型转换有两种常见的形式：</p>
<p>(BaseClass)obj </p>
<p>obj <span class="kwrd">as</span> BaseClass</p>
<p>同时，Convert类也提供了很多常用类型的转换接口。</p>
<p>我接下来要说的是第一种转换形式。</p>
<p>当使用第一种转换形式的时候，要求obj是null，或者是一个BaseClass类或其派生类实例。否则转换会抛出异常（使用后一种形式则返回null）。这倒好理解，但是对于简单类型，就比较容易出错了。</p>
<pre class="csharpcode"><span class="kwrd">object</span> obj = 2;
<span class="kwrd">double</span> i = (<span class="kwrd">double</span>)obj;</pre>
<p>上面的代码会抛出一个InvalidCastException，这是因为使用前一种类型转换的时候，CLR运行时会进行类型匹配，因为obj的类型（int）和double不相匹配——虽然看起来是无损精度的转换——因此抛出异常。从这个例子中我们可以得到一个结论：</p>
<blockquote>
<p>除非你非常确定你要转换的源对象是什么类型，否则千万使用第一种形式，特别是对于简单类型更是如此。</p>
</blockquote>
<p>对于简单类型，建议采用Convert.ToXXX接口实现转换，可维护性高一些。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/csharp" title="CSharp" rel="tag">CSharp</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e7%b1%bb%e5%9e%8b%e8%bd%ac%e6%8d%a2" title="类型转换" rel="tag">类型转换</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/c%e4%b8%adreadonly%e5%92%8cconst%e7%9a%84%e5%8c%ba%e5%88%ab.html" title="C#中Readonly和const的区别 (2009/11/12)">C#中Readonly和const的区别</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/%e9%9a%8f%e6%9c%ba%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%94%9f%e6%88%90%e5%87%bd%e6%95%b0.html" title="随机字符串生成函数 (2009/03/23)">随机字符串生成函数</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/%e6%85%8e%e7%94%a8%e7%b1%bb%e5%9e%8b%e5%bc%ba%e5%88%b6%e8%bd%ac%e6%8d%a2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C#中Readonly和const的区别</title>
		<link>http://www.imkevinyang.com/2009/11/c%e4%b8%adreadonly%e5%92%8cconst%e7%9a%84%e5%8c%ba%e5%88%ab.html</link>
		<comments>http://www.imkevinyang.com/2009/11/c%e4%b8%adreadonly%e5%92%8cconst%e7%9a%84%e5%8c%ba%e5%88%ab.html#comments</comments>
		<pubDate>Thu, 12 Nov 2009 06:05:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[Const]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Readonly]]></category>
		<category><![CDATA[只读]]></category>
		<category><![CDATA[常量定义]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/c%e4%b8%adreadonly%e5%92%8cconst%e7%9a%84%e5%8c%ba%e5%88%ab.html</guid>
		<description><![CDATA[<p>这个问题其实很常识。写代码的时候突然想到的，作此备忘。</p>
<p>const和readonly这两个关键字都是用来表示常量，只不过标记为Readonly的变量可以在构造函数中动态赋值，const需要在变量声明的时候就初始化；如果将这两种常量放到单独的动态链接库中，然后编译整个项目，则应用程序对于readonly&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>这个问题其实很常识。写代码的时候突然想到的，作此备忘。</p>
<p>const和readonly这两个关键字都是用来表示常量，只不过标记为Readonly的变量可以在构造函数中动态赋值，const需要在变量声明的时候就初始化；如果将这两种常量放到单独的动态链接库中，然后编译整个项目，则应用程序对于readonly变量，是每次都从动态链接库中读取最新的常量值，而对于const变量是在编译的时候就写死到应用程序代码中了（我不知道这是不是编译器优化行为，反正我在VS2008下无论是Debug版本还是Release版本均是这样的行为）。</p>
<p>后面一点很重要，举一个简单的例子。我新建了两个工程，一个应用程序，一个是类库。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb9.png" width="168" height="160" /></p>
<p>其中ClassLibrary1中定义了StaticResources类</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> StaticResources
{
    <span class="kwrd">public</span> <span class="kwrd">const</span> <span class="kwrd">int</span> ConstVar = 1000;
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> <span class="kwrd">int</span> ReadonlyVar = 1000;
}</pre>
<p>在ConsoleApplication5中代码如下：</p>
<pre class="csharpcode"><span class="kwrd">class</span> Program
{
    <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)
    {
        Console.WriteLine(<span class="str">&quot;Const Variable is {0}&quot;</span>, StaticResources.ConstVar);
        Console.WriteLine(<span class="str">&quot;Readonly Variable is {0}&quot;</span>, StaticResources.ReadonlyVar);
    }
}</pre>
<p>输出都是1000没有问题。</p>
<p>当写类库的人突然因为种种原因需要更新ConstVar和ReadonlyVar这两个常量，假设更新为2000。更新完之后，他觉得主应用程序没有做修改，就没有更新，只发布了最新的dll。结果呢，ReadonlyVar更新了，ConstVar没有更新。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb10.png" width="225" height="42" /></p>
<p>对于Asp.net网站应用程序就更容易出现这样的问题了。一般我们引用的动态链接库都是放在网站下的bin目录。因为更新网站相对比较麻烦，所以有时候我们会偷懒，只更新动态链接库，这个时候就很容易出现上述的问题了。</p>
<p>鉴于此，一般我在定义常量的时候比较偏向于使用static readonly组合关键字。虽然有稍许的性能缺失，但是带来的更好的可维护性。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/const" title="Const" rel="tag">Const</a>, <a href="http://www.imkevinyang.com/tags/csharp" title="CSharp" rel="tag">CSharp</a>, <a href="http://www.imkevinyang.com/tags/readonly" title="Readonly" rel="tag">Readonly</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%8f%aa%e8%af%bb" title="只读" rel="tag">只读</a>, <a href="http://www.imkevinyang.com/tags/%e5%b8%b8%e9%87%8f%e5%ae%9a%e4%b9%89" title="常量定义" rel="tag">常量定义</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/%e6%85%8e%e7%94%a8%e7%b1%bb%e5%9e%8b%e5%bc%ba%e5%88%b6%e8%bd%ac%e6%8d%a2.html" title="慎用类型强制转换 (2009/11/12)">慎用类型强制转换</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/%e9%9a%8f%e6%9c%ba%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%94%9f%e6%88%90%e5%87%bd%e6%95%b0.html" title="随机字符串生成函数 (2009/03/23)">随机字符串生成函数</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/c%e4%b8%adreadonly%e5%92%8cconst%e7%9a%84%e5%8c%ba%e5%88%ab.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DotNet中未退订事件引起的内存泄露问题</title>
		<link>http://www.imkevinyang.com/2009/11/dotnet%e4%b8%ad%e6%9c%aa%e9%80%80%e8%ae%a2%e4%ba%8b%e4%bb%b6%e5%bc%95%e8%b5%b7%e7%9a%84%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e9%97%ae%e9%a2%98.html</link>
		<comments>http://www.imkevinyang.com/2009/11/dotnet%e4%b8%ad%e6%9c%aa%e9%80%80%e8%ae%a2%e4%ba%8b%e4%bb%b6%e5%bc%95%e8%b5%b7%e7%9a%84%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Thu, 12 Nov 2009 06:04:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[DotNet]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[内存]]></category>
		<category><![CDATA[内存泄露]]></category>
		<category><![CDATA[委托]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/dotnet%e4%b8%ad%e6%9c%aa%e9%80%80%e8%ae%a2%e4%ba%8b%e4%bb%b6%e5%bc%95%e8%b5%b7%e7%9a%84%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e9%97%ae%e9%a2%98.html</guid>
		<description><![CDATA[<p>今天在InfoQ上看到一篇文章<a title="处理.NET中的内存泄露" href="http://www.infoq.com/cn/news/2009/11/Memory-Leaks-.NET" target="_blank">处理.NET中的内存泄露</a>，里头提到说DotNet内存泄露的几种常见情况，</p>
<ul>
<li>使用静态引用 <strong><font color="#008000"></font></strong></li>
<li>未退订的事件－作者认为这是最常见的内存泄漏原因 </li>
<li>未退订的静态事件 </li>
<li>未调用Dispose方法 </li>
<li>使用不彻底的Dispose方法 </li>
<li>在Windows Forms中对BindingSource的误用 </li>
<li>未在Wo&#8230;</li></ul>]]></description>
			<content:encoded><![CDATA[<p>今天在InfoQ上看到一篇文章<a title="处理.NET中的内存泄露" href="http://www.infoq.com/cn/news/2009/11/Memory-Leaks-.NET" target="_blank">处理.NET中的内存泄露</a>，里头提到说DotNet内存泄露的几种常见情况，</p>
<ul>
<li>使用静态引用 <strong><font color="#008000"></font></strong></li>
<li>未退订的事件－作者认为这是最常见的内存泄漏原因 </li>
<li>未退订的静态事件 </li>
<li>未调用Dispose方法 </li>
<li>使用不彻底的Dispose方法 </li>
<li>在Windows Forms中对BindingSource的误用 </li>
<li>未在WorkItem/CAB上调用Remove </li>
</ul>
<p>当时对于第二点，“未退订事件”引起的内存泄露不是很理解。后来仔细分析了一下，又参考了MSDN上关于事件和委托的解释，终于意识到了自己以前没有注意的一个问题。</p>
<blockquote><p>假设，类A提供了一个事件，类B和类C均订阅了该事件。如果类B和类C的实例不再使用了，而又没有显式退订此事件，那么类B和类C的实例将不会被GC回收，直至类A实例被销毁为止。</p>
</blockquote>
<p>下面的代码说明了这种情况：</p>
<pre class="brush: csharp">public class Container
{
	private List&lt;Containee&gt; _controls = new List&lt;Containee&gt;();

	public List&lt;Containee&gt; Controls
	{
		get { return _controls; }
		set { _controls = value; }
	}
	private String _currentState;

	public event EventHandler StateChanged;

	public String CurrentState
	{
		get
		{
			return _currentState;
		}
		set
		{
			if (value != _currentState)
			{
				_currentState = value;
				if (StateChanged != null)
				{
					StateChanged(this, null);
				}
			}
		}
	}

	public void ClearControls()
	{
		_controls.Clear();
	}
}

public class Containee
{
	private String _name;
	private Container _container;
	public Containee(String controlName, Container container)
	{
		_name = controlName;
		_container = container;
		_container.Controls.Add(this);
		container.StateChanged += OnStateChanged;
	}

	public void OnStateChanged(object sender, EventArgs e)
	{
		Container container = sender as Container;
		if (container != null)
		{
			// Do something....
			Console.WriteLine(&quot;{0}: State change, current state is {1}.&quot;, _name, container.CurrentState);
		}
	}
}
class Program
{
	static void Main(string[] args)
	{
		Container container = new Container();
		new Containee(&quot;Control 1&quot;, container);
		new Containee(&quot;Control 2&quot;, container);
		new Containee(&quot;Control 3&quot;, container);
		container.CurrentState = &quot;State1&quot;;

		Console.WriteLine(&quot;================================================&quot;);
		// 清除所有子控件
		container.ClearControls();
		// 添加新控件进来
		new Containee(&quot;Control 4&quot;, container);
		new Containee(&quot;Control 5&quot;, container);
		new Containee(&quot;Control 6&quot;, container);
		container.CurrentState = &quot;State2&quot;;
	}
}</pre>
<p>运行结果：</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb8.png" width="387" height="159" /></p>
<p>如上述结果看到的，尽管旧控件已经被clear掉了，但是它们仍在起作用。</p>
<p>当我们在后面代码中将container容器上的控件清除掉的时候，我们会习惯性的以为这些控件已经不再被引用了，资源会被自动回收掉。而设计Containee的人可能在写事件订阅的时候也不会想起背后的逻辑，习以为常的觉得，只要在代码里找到该Containee实例都被“=”给了谁，然后把它的引用置为null就行了。殊不知，C#的event-delegate模型下，当一个类实例订阅了一个事件的时候，此实例已经被隐式的传给了“事件”了（CLR的事件模型是建立在委托System.Delegate之上的，事件可以看成是一个委托类）。因此，只要Container不销毁，事件也就不销毁，Containee的实例就不会被回收，除非Containee退订了该事件。</p>
<p>自己在写事件处理的时候根本没有考虑过这样的问题，不知道以前写过的代码会不会也存在这样的问题。不管怎么，以后得注意一些了。</p>
<p style="text-align: right">——<a title="DotNet中未退订事件引起的内存泄露问题" href="http://www.imkevinyang.com/2009/11/dotnet%E4%B8%AD%E6%9C%AA%E9%80%80%E8%AE%A2%E4%BA%8B%E4%BB%B6%E5%BC%95%E8%B5%B7%E7%9A%84%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E9%97%AE%E9%A2%98.html"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/dotnet" title="DotNet" rel="tag">DotNet</a>, <a href="http://www.imkevinyang.com/tags/%e4%ba%8b%e4%bb%b6" title="事件" rel="tag">事件</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e5%86%85%e5%ad%98" title="内存" rel="tag">内存</a>, <a href="http://www.imkevinyang.com/tags/%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2" title="内存泄露" rel="tag">内存泄露</a>, <a href="http://www.imkevinyang.com/tags/%e5%a7%94%e6%89%98" title="委托" rel="tag">委托</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/09/%e9%87%8a%e6%94%besql-server%e5%8d%a0%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98.html" title="释放SQL Server占用的内存 (2009/09/01)">释放SQL Server占用的内存</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/dotnet%e4%b8%ad%e6%9c%aa%e9%80%80%e8%ae%a2%e4%ba%8b%e4%bb%b6%e5%bc%95%e8%b5%b7%e7%9a%84%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: enhanced

Served from: www.imkevinyang.com @ 2012-02-09 10:35:58 -->
